Posts Tagged ‘DOM’

Contextual SCRIPT tags

Posted in 'Code Snippets, JavaScript' by James on August 31st, 2009

Here’s a nifty little trick that allows you to write “contextual” JavaScript. It’s incredibly obtrusive and probably shouldn’t be used at all but it’s still a pretty cool idea:

<div id="some-div">
    <script type=":contextual">
        alert(this.id); // "some-div" is alerted
    </script>
</div>

Instead of the this keyword referencing the global object (window) we can make it reference the parentNode of the script element. Here’s the code that makes it work:

(function(){
 
    var scripts = document.getElementsByTagName('script'),
        script, i = 0;
 
    while ( (script = scripts[i++]) ) {
        if ( /:contextual$/.test(script.type) ) {
            (new Function(script.innerHTML)).call(script.parentNode);
        }
    }
 
})();

Take it or leave it! – I’m indifferent either way – yes, it’s obtrusive but you’ve got to admit, contextual JavaScript looks pretty neat!

JavaScript: Bad Practices

Posted in 'JavaScript' by James on August 17th, 2009
JavaScript: Bad Practices

I’ve seen a lot of curious (bordering on horrific) code in my life; and I’d say about half of it was written by me. If you don’t attest to the fact that you once wrote crap code then you’re either a liar or perhaps, have omnipotent powers!

Here’s a relatively small collection of what I see as bad JavaScript practices; in other words – a list of how to write really really ugly JavaScript that will break! I know it’s quite a negative angle to take but it’s easier than writing a post on best practices, plus it gives me a chance to vent! Many of these are things I’ve done in the past; I’ve since discovered the errors in my ways.

Non-constructor identifiers beginning with a capital letter

Variable names should only begin with a capital if they’re pointing to constructor functions. Doug Crockford has more:

There is a convention that all constructor functions are named with an initial capital, and that nothing else is spelled with an initial capital. This gives us a prayer that visual inspection can find a missing new.

Not following conventions will only get you in trouble! So, to be clear, this is all wrong:

var Color = 'red';
var SomeNumber = 234;
var AnArray = [1,2,3];
var Foo = { bar: 123 };
// None of them should start with a capital letter!

Only functions that are constructors should be identified with an initial captial letter, not regular functions. E.g.

/* This is a regular function. */
function sum() {
    var total = 0, i = 0, len = arguments.length;
    for ( ; i < len; ++i ) {
        total += arguments[i];
    }
    return total;
}
 
/* This is a constructor function */
function Widget(innerText, styles) {
    this.innerText = innerText;
    this.cssStyles = styles;
}

Not using the var statement to define variables

Not using the var statement when defining variables for the first time is a very bad idea. These variables will become part of the global scope. This sucks because you won’t get any warning. Not only is it a bad practice but it can have a negative affect on performance, after-all, the further away a scope is the longer it takes to access. So, always use the var statement:

foo = 3; // NO!
var foo = 3; // YES

Prefixing every new variable in a given scope with var

There's no point in having several var statements if you only need one:

var someVar1 = 'a';
var someVar2 = 'b';
var someVar3 = 'c';
 
// Much easier:
var someVar1 = 'a',
    someVar2 = 'b',
    someVar3 = 'c';

Using non-strict comparison operators, and then comparing across different types

There are two classes of comparison operators; those that type-cast (==/!=) when required and those that don't (===/!==). You don't ever want to use the former!

1 == "1"; // true
false == " \n\t "; // true
[[],[]] == true; // true
 
// ... Confused?

See? It's obviously a bad idea! Please only ever use strict-equality comparison operators; they'll check that the two operands are identical, not just "equal":

1 === "1"; // false
false === " \n\t "; // false
[[],[]] === true; // false
 
// Just as expected!

Not "caching" non-varying complex objects

This is vitally important; if you're going to be repeatedly using an object you should name it and save it! A basic example:

Third party JavaScript – an improvement

Posted in 'JavaScript' by James on August 11th, 2009

If you’ve ever released a JavaScript widget, one which people can include within their site or even if you’re one of those people that has had to copy one of those ugly chunks of code and somehow come to terms with placing it in your previously clean HTML, I’m sure you’ll appreciate a cleaner and less scarring alternative. After all, anything’s got to be better than this:

<div id="widget_133332_g_foobar"></div>
<script>
    widget_133332_v_height = '233px';
    widget_133332_v_width = '200px';
    widget_133332_h_align = true;
    widget_133332_v_align = false;
    widget_133332__debug = false;
    widget_133332_id = 'Foo';
</script>
<script src="http://some-widget-url.com/script?id=widget_133332"></script>

And within script?id=widget_133332 there will be something like this:

document.write('<div id="widget_133332">...</div>');
document.write('<div id="widget_133332_a_sec">...</div>');
document.write('<div id="widget_133332_b_sec">...</div>');
document.write('<div id="widget_133332_c_sec">...</div>');

I’m not complaining; it’s not all that bad. However it could be done better; much better!

I decided to have a proper go at creating one of these. There were a couple of barriers to completion that required some extra work along the way; I’m releasing that extra work as a small stand-alone library that you can use within your 3rd party scripts. Here’s an example chunk-of-code:

<script src="http://some-service.com/widget.js?id=2323">
({
    width: 200,
    height: 400,
    id: 'my-widget',
    keywords: ['apple', 'orange', 'banana']
})
</script>

Nicer to look at and much easier to use than the status quo! The JSON-like syntax is very easy-to-follow, even if you’ve never seen anything like it. The library used to enable this unique technique is called embedHelper.

Introducing “mini”

Posted in 'Cool Stuff, JavaScript' by James on August 9th, 2009
Introducing “mini”

Today I’m releasing my first attempt at creating a “selector engine”; it’s called mini! I’m not sure if this really qualifies as a “selector engine” though; it does not entirely support any particular CSS specification; instead, I’ve built it to work with only the most commonly used selectors.

While the work done on engines such as Peppy, Sizzle and Sly (and others…) is commendable the CSS3-support aspect is totally lost on some users. Resig’s post on “Selectors that People Actually Use” attests to this.

mini has been built to support only the most frequently used CSS selectors. If you prefer CSS3-selector wizardry then you won’t like this, at all!

mini supports the following selectors (and variations):

  • div
  • .example
  • body div
  • div, p
  • div, p, .example
  • div p
  • div > p
  • div.example
  • ul .example
  • #title
  • h1#title
  • div #title
  • ul.foo > * span

Don’t try and do anything fancy with it! It doesn’t support pseudo-selectors, type selectors or any combinators (other than >).

The entire script weighs in at about 1.5kb (minified) and only 850 bytes (minified and gzipped). It’s quite fast too:

Zakas’ JavaScript performance tips

Posted in 'JavaScript' by James on August 8th, 2009
Zakas’ JavaScript performance tips

Nicholad Zakas, who wrote this book, recently spoke about JavaScript performance at Google; his presentation was called “Speed Up Your JavaScript” and it’s available to view on Youtube.

In the presentation Nicholas covers areas rarely talked about; he takes a low-level approach by explaining what’s happening behind the scenes when you do something as simple as creating or requesting a variable in JavaScript. It’s not all conjecture though; he has a number of graphs comparing performance across browsers and then details the steps you can take to optimise your code, in order to protect yourself from less-than-satisfactory JavaScript implementations (IE comes to mind).

I’m not obsessed about performance by any means but I do think that the practices shared in his presentation should be followed to the letter. Speed and performance are hot topics on the client-side; our users demand fast and responsive applications/websites.

His advice:

Five key points emerged during the presentation:

  • Store out-of-scope variables in local variables.
  • Minimise property access.
  • Do as little as possible on each iteration of a loop.
  • Minimise document reflow by only changing the DOM when absolutely necessary.
  • Don’t use inline styles unless you’re animating.

Store out-of-scope variables in local variables

The idea behind this technique is to minimise the amount of work required to get at the variable you want. The further away it is (in the scope chain) the longer it’s going to take to retrieve it. The performance cost is normally marginal but it’s still a good practice. Here’s an example:

Avoiding DOM flickering

Posted in 'Code Snippets, JavaScript' by James on July 23rd, 2009

DOM flickering occurs when you hide elements using JavaScript and there’s a noticeable delay between the page being loaded and the element actually hiding. This usually happens because you’re handling the removal upon the onload event; this is generally a bad idea – this event will not fire until everything has loaded, including images!

It’s considered better practice to use one of the various domReady abstractions available. Unfortunately, this won’t always work either, especially with large DOM structures! One method I’ve been using recently to avoid the flicker is to add a class to the body element as soon as it exists, thereby making it possible to affect the styling of these elements before they even exist within the DOM! An example:

<!-- SIMPLIFIED -->
<html>
    <head>
        <style type="text/css">
            body.js .nojs { display: none; }
        </style>
    </head>
    <body>
 
        <!-- BODY element exists! -->
        <script>
            document.body.className += ' js';
        </script>
 
        <div class="nojs">
            ... No flicker!
        </div>
 
    </body>
</html>

Or, more cleanly:

<!-- SIMPLIFIED -->
<html>
    <head>
        <style type="text/css">
            html.js .nojs { display: none; }
        </style>
        <script>
            // Add class to <html> element
            document.documentElement.className += ' js';
        </script>
    </head>
    <body>
 
        <div class="nojs">
            ... No flicker!
        </div>
 
    </body>
</html>

How do you solve the “flicker” problem?

Special scroll events for jQuery

Posted in 'JavaScript' by James on July 10th, 2009
Special scroll events for jQuery

After recently considering the impact of a native DOM implementation of two possible scroll events; “scrollstop” and “scrollstart”, I eventually came to the realisation that it would probably be a bad idea. Consider these two potential events yourself – what would initiate the “scrollstop” event? – how does the browser know when a user has stopped scrolling; it can’t just fire the event on every single step of a scroll (like the native “scroll” event)…

No, the only way to even simulate such an event would be to have a delay between the last scrolling action and the event itself – a timer could start on every “scroll” event and then if that timer is not cleared in time (say 500 milliseconds) then it can be assumed a user has “stopped scrolling”, or, has taken a break from a lengthy scroll; either circumstance warrants a “scrollstop” event in my opinion.

While we’re at it we may as well add a “scrollstart” event – this will only fire once at the start of each scrolling session.

I had always wanted a decent psuedo-event to create using jQuery’s cool “Special Events” API – when I first heard about it I wasn’t sure how I might make use of it. By the way, jQuery uses this technique to implement the non-cross-browser “mousenter” and “mouseleave” events as well as the infamous “ready” event! Here, we can use it to create our two new events, “scrollstart” and “scrollstop”.

Because of jQuery’s (relatively) simple API, creating these new events couldn’t be much easier:

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.

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:

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!