the world is round
i'll prove it

Unobtrusive Value

Posted On: January 2nd, 2008 by chris

Sorry to keep the trend of meta-blogging but my life really is that boring otherwise so here goes…

In my last post I decided to let everyone know how I went about implementing that nice little search form trick of having the form input itself be its own label. Just check out the post for the details. Looking at this it was a working solution but it seemed ugly and as though there was too much of my code there. So lets see what I’ve done now.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

var DefaultField = Behavior.create({
  initialize: function(options) {
    this.options = Object.extend({ className: 'default' }, options || {});

    if (!this.options.defaultText)
      throw new Error('FieldDefault: Must provide defaultText value');

    this.onblur();
  },
  onblur: function() {
    if (this.element.value.blank())
      this.element.addClassName(this.options.className).value = this.options.defaultText;
  },
  onfocus: function() {
    if (this.element.value == this.options.defaultText)
      this.element.removeClassName(this.options.className).clear();
  }
});

Event.addBehavior({ '#q': DefaultField({ defaultText: 'live search...' }) });

It’s not particularly shorter or cleaner, in fact I really hate the fact that almost every line has this.element in it multiple times but there’s one important difference between this code and its predecessor, it’s re-usable! The previous implementation was directly attached to the element and did not allow for any re-usability without being duplicated. Now I can re-use this behavior in a test suite and quickly verify it’s function in many browsers very quickly. I can also use this behavior elsewhere that similar functionality is desired and I don’t have to copy and paste the code.

There’s also a hidden value to this technique. Had I re-used the previous implementation over several portions of a larger system and then decided to change how the default value was displayed, say I wanted to make it an overlay so it doesn’t impact other behaviors like live search where you may want to observe the field value for changes to fire off a search, I’d have to go modify at least a few of these implementations. This modification would have left me with different implementations of the same idiom without any way of telling them apart without digging through the code. By bottling this up in a behavior I can have multiple implementations with each having a descriptive name and appropriate documentation. More importantly, I can change all of them in a single place which makes it more maintainable.

Again, if it wasn’t obvious this post relies upon prototype.js and now also upon LowPro. Check these libraries out if you haven’t already and make sure to look at them from the perspective of not necessarily just letting you keep your JavaScript out of your HTML, but also letting you bottle that JavaScript into more re-usable chunks because after all the last thing we want to do as programmers is write more code.

Tags: javascript

Unobtrusive Search Form Default

Posted On: November 18th, 2007 by chris

This is a really simple thing that I’m sure dozens of other people have already implemented over and over by now and that’s not counting the hundreds whose Mephisto theme doesn’t do this out of the box.

Basically I wanted my new theme, wibbish, to have some sort of label for the search box. Here’s my take on creating an unobtrusive default for the form field like you see on many sites these days. The idea is simple, when the form field is not focused and has no user entered value, it should have a CSS class appended to it so that its styling clearly indicates it’s in a default state while at the same time have its value set to some sane value that would work as a label in a traditional form layout. Once the field becomes focused, that new CSS class and default value should be removed to make it easier to modify the form field.

Now to cut to the chase, here’s the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

Event.observe(window, 'load', function() {
  // grab a reference to the search field
  var q = $('q');

  // add a focus and blur handler to the search field
  Object.extend(q, {
    // set the default text as an attribute of the object so it's only set once
    defaultText: 'Search',

    // simple onBlur handler to add a "default" class and text to the field
    onBlur: function() { if (this.value == '') this.addClassName('default').value = this.defaultText; },

    // simple onFocus handlers to remove the "default" class and text from the field
    onFocus: function() { if (this.value == this.defaultText) this.removeClassName('default').clear(); }
  });

  // attach our handlers
  q.observe('blur', q.onBlur.bindAsEventListener(q)).observe('focus', q.onFocus.bindAsEventListener(q));

  // finally just trigger the onBlur event handler to initialize everything
  q.onBlur();
});

Of course, now that I’m done with this, it’s time to try writing a plugin or patching Mephisto to have an unobtrusive live search.

Update: As if it wasn’t obvious, this is all based upon the excellent prototype library.

Tags: javascript