Archive for the ‘JavaScript’ Category

How to avoid switch-case syndrome

Posted in 'JavaScript' by James on July 4th, 2009
How to avoid switch-case syndrome

This is the first post of a hopeful series dubbed “JavaScript, tip of the week“; I will try to release a tip in some form every week.

I’m young and haven’t been doing this programming thing for very long so the fact that I’ve never had to use a switch-case statement (to my recollection) might not be very impressive; actually you probably see this as a bad thing and you might even be wondering why I haven’t. I can’t really explain why but I seem to have an inherent dislike of things like this:

switch (something) {
 
    case 1:
        doX();
    break;
 
    case 2:
        doY();
    break;
 
    case 3:
        doN();
    break;
 
    // And so on...
 
}

The fictional author of this code obviously doesn’t know enough about JavaScript to make use of its various other constructs, most of them ten times more suited to this situation than an ugly switch statement. It’s not its appearance that truly annoys me though; it’s the knowledge that there are so many easier and more graceful ways of achieving such functionality.

Switch statements are considered as useful when you have a single variable and dependent on its value you want to carry out one of a number of different tasks. Using multiple if-else clauses doesn’t seem appropriate so the switch statement is often called upon to lend a hand. I’m sure most of you are familier with it and have seen it more than once before.

Let’s take the example from above; dependent on the value of something we run doX, doY or doN. In JavaScript, the same logic can be expressed with a simple lookup table in the form of an object:

var cases = {
    1: doX,
    2: doY,
    3: doN
};
if (cases[something]) {
    cases[something]();
}

Not only is this cleaner but it’s also reusable, modifiable and accessible… All the conditions are saved as part of an object, so if you ever need to recall or change those conditions then it’s as easy as cases[condition].

I suspect this covers about 90% of situations where a switch-statement is used; the remaining 10% are probably legitimate uses. Using a lookup table as an alternative to the Switch statement is not new; in fact this is the only way such logic can be expressed in both the Python and Lua languages, both of which have no support for switch statements.

So, my message is the following: do not use switch-case constructs unless absolutely necessary. Why? - Because there are better alternatives; simple as that!

Read more about the “Switch Statement” here: en.wikipedia.org/wiki/Switch_statement.

Retaining a reference, the simple way

Posted in 'Code Snippets, JavaScript' by James on June 27th, 2009

Something that bugs me, especially when I’m in the depths of a nasty-looking jQuery chain, is the fact that there’s no way to reference the last selection, that is, without explicitly assigning it to a variable.

Look at the following code:

$( '#something' ).width( this.parent().innerWidth() ); /* NOT POSSIBLE */

This is what I’d really love to be able to do ($('#something') is assigned to this in the background). But, unfortunately, there’s no way to change the value of this (because it’s immutable); plus jQuery provides us with no way to grapple the previous selection. So, unless I want to mess around with functions as setters there’s really only two ways of doing what I want:

// #1 (BAD PRACTICE - selecting twice)
$( '#something' ).width( $('#something').parent().innerWidth() );
 
// #2
var something = $('#something');
something.width( something.parent().innerWidth() );

So now we’re left with only one acceptable way of doing this; assigning $('#something') to a variable and then referencing that variable from that point onwards.

I accept that this is the “best practice” but, to be honest, I really hate it… Just looking at it; it seems unnecessary. And I don’t want to mess around with functions as setters because that just makes the code even more bloated. Instead, I’d much rather have a property under the jQuery namespace that will always be referencing the last selection. Something like this:

$( '#something' ).width( $._this.parent().innerWidth() );
/* $('#something') === $._this */

And as the code progresses, $._this is re-assigned continually; always reflecting the previous selection.

Maybe, in the future, the jQuery team will choose to implement something like this, but, for now, it’s possible using the following “hack”:

(function(_jQueryInit){
 
    jQuery.fn.init = function(selector, context) {
        return (jQuery._this = new _jQueryInit(selector, context));
    };
 
})(jQuery.fn.init);

NOTE: This is not the same as jQuery(something).prevObject.

I know its usefulness may not be immediately apparent to all of you; and I don’t blame you if you don’t find this technique appealing, but, before you make your decision, consider that its usage is quite specific and I think you’ll only really understand its appeal when you’ve encountered a situation that requires it.

“wordwrap” for JavaScript

Posted in 'Code Snippets, JavaScript, PHP' by James on June 26th, 2009

This function emulates PHP’s wordwrap. It takes four arguments:

  • The string to be wrapped.
  • The column width (a number, default: 75)
  • The character(s) to be inserted at every break. (default: ‘\n’)
  • The cut: a Boolean value (false by default). See PHP docs for more info.

The code

function wordwrap( str, width, brk, cut ) {
 
    brk = brk || '\n';
    width = width || 75;
    cut = cut || false;
 
    if (!str) { return str; }
 
    var regex = '.{1,' +width+ '}(\\s|$)' + (cut ? '|.{' +width+ '}|.+$' : '|\\S+?(\\s|$)');
 
    return str.match( RegExp(regex, 'g') ).join( brk );
 
}

Usage

wordwrap('The quick brown fox jumped over the lazy dog.', 20, '<br/>\n');
The quick brown fox <br/>
jumped over the lazy <br/>
dog.

I know there are other solutions out there; the ones I saw seemed a bit slow though, not to mention unnecessarily complicated/bloated…

Monitoring DOM properties

Posted in 'JavaScript' by James on June 23rd, 2009
Monitoring DOM properties

I recently came across a jQuery plugin that claims to emulate the functionality of Object.prototype.watch, a method inherent in all objects that enables you to watch for a property change and run a function upon that change. Of course, this isn’t available in all implementations. IE, for example, doesn’t support this but has a DOM equivalent, onPropertyChange. Both methods are useful but their slightly different functionality makes it impossible to use either of them to create a unified solution. Again we’re left to resort to the lowest common denominator, setInterval.

The jQuery plugin I mentioned attempts to use watch() if it’s available, otherwise it uses setInterval, repeatadly iterating through a stack of objects checking for changes. Even this attempt at a unified solution is futile because the functionality behind watch() is fundamentally unachievable with cross-browser JavaScript. According to this MDC documentation, the watch method not only acts as a type of event registrar for property-changes but also has the capability to define the property’s value (following the attempted change). In other words, the psuedo-event from watch() will fire before the property is actually changed, not after - the return value from the handler becomes the actual value of that property. Therefore, any attempts at emulation (for example, with setInterval) will not succeed since we’re only able to fire our psuedo-event after the change.

The following example shows how you would use watch() - at no time does the property actually change to ‘456′, it’s constantly ‘123′:

var obj = { prop: 123 };
 
obj.watch('prop', function(propertyName, oldValue, newValue){
    return oldValue;
});
 
obj.prop = 456;
 
alert(obj.prop); // 123

Additionally, watch() does not recognise internal property changes (within the DOM). If you setup a watch on the value property of an input element, even when you type into that field, your watch-handler will not execute. I’m not sure if this is intentional but it makes this technique entirely useless for monitoring DOM properties.

So, it appears that the only way to monitor DOM properties consistently across all browsers is to only use setInterval. The following plugins, watch and unwatch work quite well:

jQuery.fn.watch = function( id, fn ) {
 
    return this.each(function(){
 
        var self = this;
 
        var oldVal = self[id];
        $(self).data(
            'watch_timer',
            setInterval(function(){
                if (self[id] !== oldVal) {
                    fn.call(self, id, oldVal, self[id]);
                    oldVal = self[id];
                }
            }, 100)
        );
 
    });
 
    return self;
};
 
jQuery.fn.unwatch = function( id ) {
 
    return this.each(function(){
        clearInterval( $(this).data('watch_timer') );
    });
 
};
 
// Plus, I finally found use for jQuery.data()! ;)

These can be used on any type of object, an example:

$('input').watch('value', function(propName, oldVal, newVal){
    log('Value has been changed to ' + newVal);
});
 
// or...
 
var obj = { prop: 123 };
$(obj).watch('prop', function(propName, oldVal, newVal){
    log('Prop has been changed to ' + newVal);
});

I went ahead and created a new special event for jQuery using the plugin:

jQuery.fn.valuechange = function(fn) {
    return this.bind('valuechange', fn);
};
 
jQuery.event.special.valuechange = {
 
    setup: function() {
 
        jQuery(this).watch('value', function(){
            jQuery.event.handle.call(this, {type:'valuechange'});
        });
 
    },
 
    teardown: function() {
        jQuery(this).unwatch('value');
    }
 
};
 
// Usage:
$('input').bind('valuechange', function(){
    log('Value changed... New value: ' + this.value);
});

This event is useful when you want to be notified every single time the value of an input element changes. No native DOM event will do this.

If there’s one thiing you should take away from all this then it’s this: if you are going to try making a browser-specific feature available across all browsers you should make sure that you match the functionality precisely, otherwise it’s worthless. For example, an Array.prototype.forEach method that passes the index as the first parameter instead of the second is useless. If you can’t match the functionality then simply create your own abstraction.

Zoomer component for sale!

Posted in 'Cool Stuff, JavaScript, News' by James on June 17th, 2009
Zoomer component for sale!

ThemeForest, one of Envato’s marketplaces, has just launched a “JavaScript” category and within it my new JavaScript component, “Zoomer“. As the description states, “‘Zoomer’ enables your users to closely inspect images by hovering their cursor over them. It’s been built as a robust, unobtrusive and highly customizable jQuery plugin.” Here’s a brief overview of its key features:

  • A fully customizable zoomer for use with any image
  • Works in all modern browsers (including IE6 )
  • This is a progressive enhancement; images will still be viewable when JavaScript is not available.
  • The Zoomer itself is highly customizable.
  • The Zoomer requires NO images – the shadows/gradients are dynamically generated by JavaScript (using VML /Canvas technologies)
  • In-depth documentation including two videos and an FAQ !

See the demo

It’s customizable!

Almost every aspect of the zoomer is customizable, here’s a preview of the jQuery options:

$.zoomer.defaultOptions = {
    zoomerClass: '_zoomer',
    zoomSrc: '',
    height: 150,
    width: 150,
    mousewheelZoom: true,
    defaultZoom: 2,
    maxZoom: 5,
    minZoom: 1,
    feedback: function(x,y,zoom){},
    onOver: function(){},
    onOut: function(){},
    zoomerOverlay: {
        className: '_zoomer-overlay',
        shadowWidth: 10,
        shadowOpacity: 0.5,
        /* Must be in "rgb(r,g,b)" format */
        shadowColor: 'rgb(0,0,0)',
        radialOpacity: 0.4,
        /* Must be in "rgb(r,g,b)" format */
        radialColor: 'rgb(0,0,0)'
    }
};

Even the shadow beneath the Zoomer is customizable - this is possible thanks to canvas/VML technologies.

Buy Zoomer (currently $5)!

Metadata within HTML comments

Posted in 'Code Snippets, JavaScript' by James on June 15th, 2009

Recently, I discussed the pitfalls of using custom HTML attributes and “expando” DOM properties to store per-element data. Thanks to the comments on that post I now understand that doing so is sometimes hard to avoid. Some people resort to using jQuery’s “metadata” plugin which can massively simplify the process of adding metadata (i.e. data about data). I’ve been meaning to post a technique I’ve been using recently; keeping data in HTML comments and then extracting it and tying it to the closest (parent) element.

With this technique you can do the following:

<div id="foo">
    <!-- { someData: 123, aString: "bar" } -->
    <p> ... regular content ... </p>
</div>
 
<!-- Regular comments can still be used -->
 
<p><!--{specialID:1234}-->... comment-data is tied to the parent element...</p>

Using the “commentData” function you can extract that information and use it within your JavaScript, e.g.

var foo = document.getElementById('foo');
 
var fooData = commentData( foo ); // => {someData: 123, aString: "bar"}
fooData.someData; // <= 123

Download “commentData” from Github

It’s just an API

Posted in 'HTML/XHTML, JavaScript' by James on June 9th, 2009
It’s just an API

Thousands of developers interact with this API on a daily basis yet most forget it is just… an API! Of course, I’m talking about the notorious “Document Object Model” (a.k.a the DOM). With the rise of “Rich Internet Applications” interaction with the DOM has sky-rocketed and as a result it’s being heavily abused!

Have you ever needed to do this? -

// E.g. 1
element.addEventListener('click', function(e){
    this.rel += ' clicked' + '(' + e.clientX + ' ,' + e.clientY + ')';
});
 
// E.g. 2
jQuery('a').mouseover(function(){
    var color = jQuery(this).css('color');
    jQuery(this).data('beforeColor', color);
    changeColor(this);
});

If you have then (in my humble opinion) you’re abusing the DOM!

The first example is obviously bad practice; using HTML attributes to track changes unrelated to the HTML content is a crime of sorts and should never be done! The second example probably doesn’t seem as bad to most developers. jQuery’s “data” method allows you to store expando-like data about an element without obtrusively defining it as a direct property. This technique of storing element data is far better than using the HTML rel attribute. Or is it?

I was an advocate of this particular technique but I’ve come to realise that it is, in most situations, no better than using any random HTML attribute. If we put the unobtrusive-vs-obtrusive argument aside, both techniques are effectively the same. Plus, jQuery’s “data” technique is not really unobtrusive - jQuery still uses an expando property to tie the element to a particular property in a JavaScript object; I’m not saying there’s anything wrong with this, I’m just pointing out the common misconception that using jQuery’s data method is somehow cleaner than using a random or made-up HTML attribute (/DOM property).

The main reason I am now so sceptical about its usage is because, over time, I’ve seen a lot of cases that don’t really require it at all and could quite easily be achieved with a well-thought-out use of JavaScript closures. Obviously it’s not all bad; there are a few valid uses - for example, jQuery currently uses its own “data” method to tie events to elements/objects; a central part of the its event dispatch system.

Magical closures

The nature of JavaScript closures allows us to use regular variables to store progress or states and then access those variables from within nested functions. I’ve put together a short example; this is an outline of a drag-and-drop script:

// Library neutral/agnostic
 
draggableElements.forEach(function(elem){
 
    var down = false,
        y = 0,
        x = 0;
 
    elem.bind('mousedown', function(e){
        down = true;
        x = e.pageX - getOffset(elem).left;
        y = e.pageY - getOffset(elem).top;
    });
 
    document.bind('mousemove', function(e){
        if (down) {
            elem.applyCSS({
                left: e.pageX - x,
                top: e.pageY - y
            });
        }
    });
 
    document.bind('mouseup', function(e){
        down = false;
    });
 
});

Every “draggable” element is given its very own closure (through forEach) within which we can define numerous variables accessible in each of the nested “handler” functions (’mousemove’, ‘mousedown’, etc.). No expando properties are required, nada!

I haven’t got much more to say about this; the above code pretty much sums up my point!

I’m interested in valid uses of jQuery’s data() method (other than those used in the core); someone please enlighten me!

Best practices & JSLint

Posted in 'JavaScript' by James on June 7th, 2009
Best practices & JSLint

JSLint” is a JavaScript “code quality tool”. If you’ve never heard of it then think of it as the W3C HTML validator, but for JavaScript. Doug Crockford, the genius that created JSLint, frequently claims that JavaScript is “The World’s Most Misunderstood Programming Language”; if you want to know where he’s coming from with this statement then you’ll have to purchase his book, “JavaScript: The Good Parts” or, for a brief overview, watch the Google Tech Talk.

In some ways JavaScript could be considered just as lax as HTML when it comes to what is acceptable and what isn’t. For example, most browsers will let you get away with HTML that looks like this:

<ul
id =list>
    <strong><li>One
    <strong><li>Two
    <strong><li>Three

And, similarly, most, if not all, browsers will let you get away with JavaScript that looks like this:

function muahaha() {
    myarray = new Array()
    myarray['name1'] = "056"
    something = parseInt( myarray['name1'] )
    if(something==56)
        for (i=0;i<myarray.length;i++) if(myarray[i] != null) return true
    return false
};

How many things can you count in the above code that are either bad practice or just incorrect usage of the language? If we go by JSLint then there are a total of 16 problems with it! Plus there are a couple that aren’t noticed by JSLint (using an array as an object & accessing myarray.length on every iteration). That’s 18 altogether! Yet, all browsers will run this code quite happily without throwing a single error.

Technically, it’s all legal JavaScript (minus the extra semi-colon at the end), so I’d expect all browsers to munch it up without complaining.

So, if it works1, then why should you take that extra step to ensure best practices; what’s the point and who will benefit?

“prettyPrint” for JavaScript

Posted in 'JavaScript' by James on June 5th, 2009
“prettyPrint” for JavaScript

Those of you following me on Github may have noticed a recently added project called “prettyPrint“.

“prettyPrint” is an in-browser JavaScript “variable dumper” similar to ColdFusions’s cfdump. It enables you to print out an object of any type in table format for viewing during debugging sessions. In combination with Firebug, “prettyPrint” will make you the best-equipped JavaScript debugger on earth! (not guaranteed)

Some of its key features:

  • Entirely independent. It requires NO StyleSheets or images.
  • Handles infinitely nested objects.
  • All native JavaScript types are supported plus DOM nodes/elements!
  • Protects against circular/repeated references.
  • Allows you to specify the depth to which the object will be printed.
  • Better browser users benefit from gradient column-headers! Thanks to HTML5 and CANVAS!
  • Allows low-level CSS customisation (if such a thing exists).
  • Fully validated with JSLint!

I’ve recorded a short screencast demonstrating a couple of prettyPrint’s features:

“prettyPrint” is entirely independent. As mentioned, it requires NO StyleSheets or images. All styles are applied directly (inline) and are customizable via the exposed config object (prettPrint.config.styles).

See the demonstration »

Using it is simple enough:

var table = prettyPrint( anyRandomThing, { /*optional options object */ } );
 
// Making the table viewable is down to you...
// e.g.
document.body.appendChild(table);

For more information visit the project’s page on Github!

PS. I’m aware that there’s an already existing “port” of ColdFusion’s cfdump - I only created my one as a personal exercise; plus none of the ones I’ve seen so far have depth control or protection against circular references. ;)

Fastest way to build an HTML string

Posted in 'Code Snippets, JavaScript' by James on May 29th, 2009

You have a massive array of items that needs to be transformed into an HTML list without causing the user any grief. There are a couple common ways of doing this:

Note: I’m not even going to bother covering direct DOM manipulation for every list item because that’d be plain stupid!

#1 - Step-by-step string concat

Not the slowest method that exists but probably the most common:

var arr = ['item 1', 'item 2', 'item 3', ...],
    list = '';
 
for (var i = 0, l = arr.length; i < l; i++) {
    list += '<li>' + arr[i] + '</li>';
}
 
list = '<ul>' + list + '</ul>';

Don’t use this. It’s inefficient, slow and ugly!

#2 - Step-by-step array pushing

var arr = ['item 1', 'item 2', 'item 3', ...],
    list = [];
 
for (var i = 0, l = arr.length; i < l; i++) {
    list[list.length] = '<li>' + arr[i] + '</li>';
}
 
list = '<ul>' + list.join('') + '</ul>';

Slightly faster than string concatenation but still not perfect…

#3 - The holy grail!

var arr = ['item 1', 'item 2', 'item 3', ...];
 
var list = '<ul><li>' + arr.join('</li><li>') + '</li></ul>';

I won’t bore you with benchmarks; you’ll just have to believe me (or test for yourself) - this is by far the fastest method!

Using native methods (like join()), regardless of what’s going on behind the abstraction layer, is usually much faster than any non-native alternative.

Browser benchmarks

Due to a request and my own curiousity I’ve conducted a quick benchmarking test. Each method was tested with a 130-item array, the length of each item varied so any optimizations on the browser’s part would not be effective. Each method was tested 1000 times; the results below show how long each browser took to complete each method 1000 times:

“String concat” (ms) “Array pushing” (ms) “Native join()” (ms)
Firefox 3 147 148 65
Opera 9 172 125 78
IE 7 500 2297 79
Chrome 2 63 88 72
Safari 4b 146 141 60
Averages 205 559 70

Surprisingly, string concatenation came out much faster than “array pushing” on average. It seems IE7 optimizes for lengthy string operations but doesn’t care much for arrays. Also, Google Chrome performed oddly; the “string concatenation” method was quicker than the “native join()”… I’m not too sure what’s going on there! Anyway, the results were mostly predictable, and, of course, “native join()” came out on top!