Applying a behavior to an element is a very common task in web applications and rich web sites. Something like an element onload event that is called whenever it?s ready, regardless of whether it?s pre-created in the html, or dynamically added.
- Converting a dropdown list (
- Converting input type=checkbox/radio into images
- Wrapping an element with a complex frame (rounded corners, shadows, opacity)
- A floating label on a textbox and hiding it on a value change or focus
The Common, Bad Solution
A standard solution will be waiting until the DOM is ready (a function that exists in every self-respecting JS library), finding all elements with a certain class and calling a JS function on that element that will attach the behavior.
Disadvantages of this solution:
- Sometimes, it takes a little while until the DOM is ready, and meanwhile, the element appears in its original, behavior-less form
- When elements are dynamically added to the DOM (innerHTML / createElement & appendChild) ? the behavior must be applied again on all new elements, manually.
- A generic solution for dynamic elements is having an interval in which looks for these elements. However, this lookup is slow and the delay may cause flickering.
Code Sample for the Bad Solution:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Or, an interval:
1 2 3 4 5 6 7 8
(The functions $.select, $.domready and $.ajax can be found in any JS library).
The Desired Solution - OhBehave
OhBehave is a neat script that is responsible for applying behaviors to elements immediately, as soon as they are available, without waiting for the rest of the DOM to load. In addition, it also applies the behavior on new dynamic elements.
You can create new elements on the fly or set an element’s innerHTML with new html tags, without worrying about attaching behaviors. An can be converted to image base on its .checked property as soon as it’s appended to the document.
If you use Ajax to get HTML from server, you shouldn’t be worried about wiring up events to elements.
How does it work?
For every browser I had to find a different solution, as each of which implements the desired functionality differently. Each of the implementations is a small browser-specific code that calls OhBehave.initialize, which receives an element and applies all behaviors needed.
The behaviors for that element are defined in its class attribute, each of which is prefixed with ?oh-behave-? (optional). E.g. oh-behave-AutoComplete, oh-behave-WrapWithFrame.
Example for a behavior
1 2 3 4 5 6 7
Firefox (Gecko Engine) - XBL
XBL, or ? XML Binding Language, is a markup language, based on XML, that is defined according to a W3C standard and is used for applying rich behavior to an element. XBL allows us to declare properties (including getters/setters), custom events (and to fire them), custom methods and custom style. The XBL is placed on an element using css:
The XML structure:
1 2 3 4 5 6 7
As for now, only the Gecko engine supports XBL, even though it?s a standard.
IE (Trident Engine) - HTC
HTC, or ? HTML Component is Microsoft?s implementation for applying rich behavior to an element. It supports more or less the same as XBL.
Safari/Chrome (WebKit Engine) and Opera (Presto Engine) - The Event DOMNodeInserted
As WebKit/Presto didn’t include XBL yet (there are some mentions in the source code but it’s still turned off probably), I had to find a different solution.
The DOMNodeInserted event (a W3C standard) is fired any time an element is inserted dynamically (innerHTML / createElement & appendChild). Through this event I look for elements that should have the behavior. The lookup is done with querySelectorAll - a method of a document or element that gets a CSS selector and returns all elements for that selector.
For elements that are already in the document, I used the DOMContentLoaded event, which may cause a small flick but the engine is so fast that I barely believe it’s noticeable.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
When the div appears on the screen, it obtains immediately the
onclick event and being wrapped with a box with 4 corners.
In the demo page there are two behaviors applied on same element: 1) Wraps the element with a frame and some other elements, 2) Attaches a click event to show current date.
In addition, there’s a button that adds more elements, dynamically and the behaviors applied automagically.