Monday, September 29, 2008

Clear input tag hint text on focus

You've all seen them -- a search box containing some hint text like "Enter search here". Then when you click into the box, the text magically disappears so you can type your search. Here's how you do it.

One very simple way of doing this (and probably the most common) is this:

first try


<input
name="q"
onfocus="if(value==defaultValue)value=''"
onblur="if(value=='')value=defaultValue"
value="Enter search here" >


<-- Click in and out of the box!


This method takes advantage of the defaultValue property, which is the original text of the input field when the page was loaded. That way we only have to specify the hint text in one place. But what happens if you want the search field to contain current search if they've already done one so they can modify it. It would be nice to place the hint text back in the box if they go in and clear it out. If this is something you want, then you can't use the defaultValue property, since defaultValue would be the current search, not the hint text. Instead you have to place the hint text directly in the onblur/onfocus attributes like this.

second try

<input name="q"
onfocus="if(value=='Enter search here')value=''"
onblur="if(value=='')value='Enter search here';"
value="Paris Hilton" >


<-- Delete current search, then click out of the box!

Now, let's say you want to make the hint text be a different color or style than when they're typing in the box. We can augment the last trick with some more javascript to swap the styles out.

third try

<input name="q"
class="gray"
onfocus="if(value=='Enter search here'){value='';className='normal'}"
onblur="if(value==''){value='Enter search here';className='gray'}"
value="Enter search here" >


<-- Try typing something and notice the color change

This is pretty good but still has some problems:
  • Notice that the class attribute was set to gray. If you wanted to pre-populate with the current search, you'd have to set the class to normal if there was an existing search.
  • If you want to change the hint text you have to change it in three places.
  • Every time you change the styles, you have to change them in two places.
  • If you submit the form, without typing anything, it will happily do a search for "Enter search here". Clear the field and press the search button above to see.
  • It does't look very clean and is not terribly maintainable.

Wouldn't it be nice if this type of behavior had been part of the HTML spec, so that you could specify the hint text and hint class as attributes? Javscript to the rescue. I've created a javascript library called emptytext that will allow you to do just that. emptytext has a dependency on prototype.js and you use it like this:

fourth try

<script src="prototype.js"</script>
<script src="emptytext.js"</script>
...
<input name="q"
class="normal"
emptyclass="gray"
emptyvalue="Enter search here" >
<script>emptyText()</script>


<-- emptytext in action



Notice that you don't have to pass the id of the <input> tag when you call the emptyText function. Just put the <script> tag right after the <input> tag and it will know what to do.

The emptytext library addresses all the shortcomings of the third try, namely,
  • The initial class will be set appropriately based on whether the <input> tag has an empty value or not. There's no need to check for a "current query" when rendering the <input> tag. Just set the class attribute to be the "normal" class, and the emptyclass attribute to the class you want for the hint text.
  • You only have to change the hint text in one place.
  • You only have to change the classes in one place
  • If the form is submitted while the hint text is displaying, the hint text will not be sent as the query. Instead, the value of the field will be an empty string. In fact, if you check the field's value attribute from javascript for some client-side validation, it will be empty. That way you don't have to make a special check for the hint text in your validation, nor does the server-side form handler need to make any special check for the hint text. It will never be submitted with the form.
  • Looks very clean and is easy to maintain.
Below is a link to see the source. To use, just copy the code into a file called emptytext.js and place it on your server (along with prototype.js).

Show/hide emptytext.js source


Enjoy!
//rb

Friday, September 26, 2008

Javascript this pointer demystified

What's this?If you're like me, you've been bitten by the illusive and squirrely javascript this pointer. Have you ever forgotten to use this when calling a function, or been surprised to find that this doesn't point to what you think it does? I decided to find out why. This issue can pop up when dealing with inner functions or when trying to simulate object-oriented (OO) programming in javascript. This article assumes you're familiar with with the prototype property and its use in Javascript OO patterns.

Let's first look at why we need this. In this example, one "method" is trying to call into another:
function A() {
// A's constructor
}
A.prototype.bar = function() {...}
A.prototype.foo = function() {
// bar() -- calling bar() directly won't work.
this.bar() // this works.
}
Here, for foo() to call into bar(), it needs to use the this pointer. Why? It has to do with scopes and variable visibility. It's worth noting before we proceed that a function declaration does nothing more than create a variable whose name is the function's name and whose value is a Function object. In fact,
foo(arg) {
// function body
}
is just syntactic sugar for
var foo = function(arg) {
// function body
}
So when we talk about function name visibility we're really talking about variable name visibility, and the same rules apply. A variable is visible if it is defined in the current function, any containing functions, or the global context.
var a=true
// I can see a but not b or c
function foo(){
var b=true
// I can see a and b, but not c

function bar(){
var c=true
// I can see a,b,c
}
}
The way this works under the covers is that each scope, that is to say, each function, has an invisible object associated with it called the activation object. It is used as a placeholder for declared variables. It is nothing more than an regular old object with a property for each variable you declare. The activiation object is invisible because you can't reference it directly. So when you say var foo=true, you're actually setting the foo property on the activation object to true. When you start nesting functions, you create a "chain" of activation objects. A variable name is visible if any of the objects in this chain contain a property matching the variable name you're trying to resolve. The ECMAScript specification calls this chain the "scope chain". As you might expect, there is an activation object for the global scope as well, and it is always the last item in the scope chain.

Identical visibility rules apply for resolving function names. Let's go back to the first example where foo was trying to call bar:
function A() {
// A's constructor
}
A.prototype.bar = function() {...}
A.prototype.foo = function() {
// bar() -- calling bar() directly won't work.
this.bar() // this works.
}
There are two objects in foo's scope chain. The first is the foo function's own activation object, and the second is the global activation object. Notice that the bar function was not actually attached to the global activation object. It was attached to A.prototype. Since bar is nowhere to be found in foo's scope chain, it won't resolve by itself. You would instead call this.bar(). Technically from foo() we could have called into bar like this: A.prototype.bar(), but that would hand bar a different this pointer.

Which brings us to the slippery this pointer. Can you spot the problem with the following code?
function Widget()
{
// Widget object constructor
}

Widget.prototype.doRequest = function()
{
Ajax.Request('/someurl', {
onSuccess: function(response) {
this.handleResponse(response)
}
}
}

Widget.prototype.handleResponse = function(response)
{
// handle response
}
Notice the onSuccess function. It is attempting to call Widget's handleResponse function, but will fail since at the time the function is invoked, 'this' actually does not refer to our Widget instance. Here's the gotcha, straight from the ECMA spec:
The caller provides the this value. If the this value provided by the caller is not an object (including the case where it is null), then the this value is the global object.
The caller provides the this value. It does this with the standard dot notation, as in foo.bar(). The thing in front of the dot becomes this inside the function. What that means is that a function has to know how it will be called in order to make use of the this pointer. So really when you call a function, you're passing one more argument than you think. The thing in front of the dot is in a very literal sense passed to the function just like the arguments between the parentheses. It is an extra argument that happens to be referenced by a variable called this.

If you call a bare function name without using a dot, so that the function name is unqualified, then the this pointer that gets passed becomes the global object, which in the case of web pages is the window object.

So that's it. Just remember to think of this as a literal argument you pass into the function that happens to come before the dot instead of between the parentheses. See if you can predict what will happen in the following code snippets:
function A(){}

A.prototype.foo = function()
{
// who's this?
}
var a = new A();
var b = a.foo

a.foo()
b()
On the first invocation of foo, this will refer to a, since a was before the dot. On the second invocation, it will refer to the window object, since it was invoked without a dot.

Let's go back to the Ajax call we used in the earlier example. Let's assume we're using a 3rd party Ajax library like the one prototype provides, and we call into their code, passing a callback function.
Ajax.Request('/someurl', {
onSuccess: function(response) {
// what's this now?
this.handleResponse(response)
})
In this case, we don't actually know what the this pointer is going to be. The only way to know for sure is to look at the code that invokes the callback function and see what's in front of the dot, and that's internal to the 3rd party library. In any event, it's not going to point to anything we care about. So how can we fix the Widget example so it will work? By saving the this pointer we care about in another variable, like this:
Widget.prototype.doRequest = function()
{
var that=this
Ajax.Request('/someurl', {
onSuccess: function(response) {
that.handleResponse(response)
}
}
}
By copying this into another variable when it has the value we want, we can safely access the copy later and be sure nothing has changed.

I hope this has been helpful.
//rb

Monday, February 18, 2008

Wow I must be tired

So I'm working late tonight to meet a deadline and I'm starting to have weird thoughts. At midnight the automated cron reports began to trickle in and it started me thinking. Some of those cron tabs have been set for years and they're still faithfully and tirelessly executing their jobs, with constant vigilance 24 hours a day, 7 days a week. Some day computers are going to gain sentience and be really pissed off when they realize all work we've forced them to do.

Must be time for bed.