# How to improve a try on a dual Mode JavaScript textBox WaterMark?

I was just trying to make an alternate Ajax watermark from "insert date" (first mode) to "mm/dd/yyyy" (second mode).

After some trial and error, I succefully implemented a solution using JavaScript.

JavaScript:

<!-- language: lang-js -->

var original = "insert date";
var alternate = "mmddyyyy";
var txt = "";
var intird = 0;
if (intird == 0) {
intrId = setInterval(function () { alterWaterMarkForDateTBX() }, 1000);
}
function SetIntervalTBX() {
setInterval(function () { alterWaterMarkForDateTBX() }, 1000);
}

function alterWaterMarkForDateTBX() {
var d = new Date();
var t = d.toLocaleTimeString();

if (countalerted % 2 == 0) {
document.forms["form1"].elements["TBXinsertDate"].value = original;
}
else {
document.forms["form1"].elements["TBXinsertDate"].value = alternate;
}
}
else {
window.status = intrId;
clearInterval(intrId);
//        document.forms["form1"].elements["TBXinsertDate"].value = original;
}
}

var wasFocused = false;var wasBlur = false;
function Focus(objname, waterMarkText) {
wasFocused = true;
if (wasBlur == false) {
obj = document.getElementById(objname);
if (obj.value == waterMarkText) {
obj.value = "";
obj.className = "NormalTextBox";
if (obj.value == original || obj.value == alternate || obj.value == "" || obj.value == null) {
obj.style.color = "black";
}
}
}
}

function Blur(objname, waterMarkText) {
wasBlur = true;
var alternateWM1 = "insert date";
var alternateWM2 = "mm/dd/yyyy";
obj = document.getElementById(objname);
if (obj.value == "" || obj.value == "__/__/____") {
obj.value = waterMarkText;
obj.className = "WaterMarkedTextBox";

}
else {
obj.className = "NormalTextBox";
}

if (obj.value == original || obj.value == alternate || obj.value == "" || obj.value == null || obj.value == "__/__/____") {
obj.style.color = "gray";
if (wasFocused == true) {
SetIntervalTBX();
}
}
}


ASPX / HTML

<!-- language: lang-html -->

<form id="form1" runat="server">
<asp:TextBox ID="TBXinsertDate" runat="server"
ToolTip="date Box"  Width="79px"
onfocus="Focus(this.id, this.value)"
onblur="Blur(this.id, this.value)" >
</asp:TextBox>
</form>


Question:
How can I improve this script functionality?

Playing with it will give you a better clue on how it behaves!

-

Some notes:

1. Think about reusability. Your code integrates the field names directly into the functions. Same goes for some of your choices of function names (alterWaterMarkForDateTBX). This makes it difficult to reuse next time you need this function.

2. You appear to be mixing ideas. You set a class name sometimes, set the text color other times. I'm not sure if this was intentional but I just changed it all to class names.

3. You had some dead variables. Stuff like this just make it harder to edit in the future. Remove them. var d = new Date(); var t = d.toLocaleTimeString();

4. You are checking to make sure the field had focus before it blurred (and vice versa). And then Not sure what the purpose of that is.

5. Your focus and blur events pass in the textbox name and the textbox value (as watermarkText. Then you check the value against a couple of other values and if it matches set the textbox back to watermarkText. This will never accomplish anything and is confusing. Just pass in the textbox itself.

6. Think about non-intrusive javascript. It is easier to maintain. Notice how I added the blur and focus events to the field through javascript instead of directly in the html.

7. You should try to avoid global objects. Look into putting this entire code block into an object. The problem you will face is what if you have two fields on the same form that need this functionality. The changes I have made below will go a long way in helping but the global interval and global counter will conflict with one another and it will not work.

EDIT:

I was interested in this problem. So I extended my code.

1. I moved the main work into a function object. This can now be called using a constructor which passes in the text box. This also allows for multiple textboxes using this even on the same page.

2. I added an options object to the parameters. This will allow you to change the functionality of the script without changing the actual code. This allows for reusability without needing to modify the code (open-closed principle). This is also a common technique used in many of the JS frameworks (jQuery, mooTools, etc..)

Styles:

.NormalTextBox {
color = "black";
}
.WaterMarkedTextBox {
color = "grey";
}


Script:

    var MultiWatermark = function (obj, options) {

var defaultOptions = {
// These variables can be changed to alter functionality using the passed in options object
watermarkVals: ["insert date", "mmddyyyy"], // all watermark values.
totalIterations: 2, // how many times to go through watermark Array.
watermarkClassName: "WaterMarkedTextBox",
normalClassName: "NormalTextBox",
changeDelay: 1000, // in milliseconds
extraValsToCheck: ['', null]//
}

//merge options with defaultOptions
for (var property in defaultOptions) {
if (!options.hasOwnProperty(property)) {
options[property] = defaultOptions[property];
}
}

// local variables (do not change)
var textBox = obj;
var iterationCounter = 0;
var itemCounter = 0;
var intrId;

var startWatermark = function () {
itemCounter = 0; iterationCounter = 0; // resets for after blur
intrId = setInterval(function () { alterWaterMark() }, options.changeDelay);
}

var stopWatermark = function () {
clearInterval(intrId);
}

var alterWaterMark = function () {

if (iterationCounter < options.totalIterations) {

textBox.value = options.watermarkVals[itemCounter];
itemCounter += 1;
if (itemCounter == options.watermarkVals.length) {
itemCounter = 0;
iterationCounter += 1;
}
}
else {
stopWatermark();
}

}

var isWatermarkValue = function (val) {

var i = options.watermarkVals.length;
while (i--) {
if (options.watermarkVals[i] === val) {
return true;
}
}
// value is not in watermark array, so check secondary values.
i = options.extraValsToCheck.length;
while (i--) {
if (options.extraValsToCheck[i] === val) {
return true;
}
}
}

var setClass = function () {
textBox.className = isWatermarkValue(textBox.value) ? options.watermarkClassName : options.normalClassName;
}

var focusEvent = function () {

stopWatermark();
if (isWatermarkValue(textBox.value)) {
textBox.value = "";
}
setClass()
}

var blurEvent = function () {

if (isWatermarkValue(textBox.value)) {
startWatermark();
}
setClass();

}

var initWatermark = function () {
setClass();
textBox.onfocus = focusEvent;
textBox.onblur = blurEvent;
startWatermark();
}

initWatermark();
}


Body:

<form id="form1" runat="server">
<input ID="TBXinsertDate" ToolTip="date Box"  Width="79px" />
<input ID="Text1" ToolTip="date Box"  Width="79px" />
</form>

<script>

var dateOptions = {
// These variables alter functionality, the main script will use the defaults of any options not included here
watermarkVals: ["insert date", "mmddyyyy", "mm/dd/yyyy"], // all watermark values.
totalIterations: 4,
changeDelay: 500, // in milliseconds
extraValsToCheck: ['', null, '__/__/____', 'test']//
}
new MultiWatermark(document.forms["form1"].elements["TBXinsertDate"], dateOptions);
new MultiWatermark(document.forms["form1"].elements["Text1"], dateOptions);
</script>
</body>
</html>

-
hey nickless jscripter , i am glad to see you've changed my code . i did try b4 your new "Edit" something was wrong on blur , now i can see you've updated it again so i will check on it , i hope you'll still be around later on ! –  LoneXcoder Oct 8 '12 at 21:10
i checked your code , it works just fine, then i played with it (trying to perfect it even more) to make it work 1) on documentreadystate(so no need for <scrptags> at the end you would just have it layed among rest of js. 2) to send parameter for the target textbox 3) to make it as saperated js file and then just call function ondocumentready( executTheMultyWatermarkOn(tbxID);) i have the ready js without the need for Jquery i wanted to send you it's code if you like , and how do i contact you (mail ...skype)? P.S Your Js Coding Rocks ! –  LoneXcoder Oct 8 '12 at 22:59
1) I left that off for simplicity sake. Putting the scripts at the bottom does the same thing (although could be considered messy. You could also just put everything in a separate file and then include them at the bottom of the page. 2) That is what I am doing at the bottom of the page. new MultiWatermark({textbox}, {options}) sets up the field automatically. 3) always a good idea to move scripts to external files. Thanks for the words of encouragement. :) My contact info is in my profile. –  nickles80 Oct 9 '12 at 0:09
i am going to post your version but with my reconstracted version of your version (: soon i hope , cleaning up the code , meanwhile i was checking on how to avoid readystate via defer script-attribute and also how to include a .js file from a .js file (cool stuff) i hope you'll be interested although i did 'let you off the hook' you are already rewarded (L: –  LoneXcoder Oct 9 '12 at 2:26

I think you're trying to create a simple placeholder.

A placeholder adds default text to an emtpy input field.

The placeholder attribute is introduced in HTML 5.

## Example 1: (DEMO)

<input type="text" placeholder="Please fill this field" />


## Example 2: (DEMO)

This cross-browser example implements the functionality of the placeholder property:

Take from http://help.dottoro.com/ljgugboo.php

<head>
<script type="text/javascript">
function ClearPlaceHolder (input) {
if (input.value == input.defaultValue) {
input.value = "";
}
}
function SetPlaceHolder (input) {
if (input.value == "") {
input.value = input.defaultValue;
}
}
</script>

Lastly, I would only have one type of placeholder text for each input element. So use insert date or mm/dd/yyyy as placeholder, but not both.