February 18, 2011

Check for duplicate DOM Id's with a simple JavaScript snippet

Yesterday I needed a cool, short and handy way of finding duplicate ID's inside the DOM of a webpage. I know there exist tons of extensions and validators but I wanted a solution with nearly no overhead.

The result is a tiny bookmarklet. After dragging it into my bookmarks bar I can analyse the current pages' DOM with one click on it.

I prepared one solution for prototype.js powered sites and one for jQuery.

If one has such an approach without relying on a 3rd party library feel free to contribute in the comments below.

Prototype version
(function () {
    var found = false;
    $$('[id]').each(function (el) {
        var ids = $$('[id=' + el.id + ']');
        if (ids.length > 1 && ids[0] === el) {
            console.warn('ID used more than once: ' + el.id, ids);
            found = true;
        }
    });
    if (!found) {
        console.log('No duplicate IDs found');
    }
})();
Bookmarklet (Drag it to your bookmarks)

JQuery version
(function () {
    var found = false;
    $('[id]').each(function () {
        var ids = $('[id=' + this.id + ']');
        if (ids.length > 1 && ids[0] === this) {
            console.warn('ID used more than once: ' + this.id, ids);
            found = true;
        }
    });
    if (!found) {
        console.log('No duplicate IDs found');
    }
})();
Bookmarklet (Drag it to your bookmarks)

Hope it comes to some use!

February 17, 2011

Private prototype methods in JavaScript

JavaScript does not know such a thing as "private methods". But it does know closures. And with this simple yet powerful tool we can implement functions that behave like private methods in an object's prototype with ease.

This is how it will look like:
var Foo = function () {};
Foo.prototype = (function () {

    // Private attributes
    var somePrivateAttribute = 'Hello world';

    // Private methods
    function somePrivateMethod(val) {
        alert(val);
    }

    // Public attributes and methods
    return {
        somePublicMethod: function () {
            somePrivateMethod(somePrivateAttribute);
        }
    };
})();

The "magic" here is the immediate function invocation. This function only returns those methods that should be public available in the prototype and holds the "private" stuff in the scope of the so created closure.

That way the "public" prototype functions have full access to the "private" members. But it is not possible to access the "private" members from anywhere besides those functions returned by the immediate function invocation.

Pretty nice stuff, isn't it? :)

To summarize this pattern we can say:
  1. Wrap the prototype members in an immediately invoked function
  2. Return those members that should be public available to the prototype
  3. Declare private attributes and methods inside the immediately invoked function but do not return them.

February 15, 2011

Static variables in JavaScript - continued

Since I had some great reactions on the first part of this post I want to give an overview of two other ways to fake static variable behaviour in JavaScript.

As Polaretto mentioned in his comments it might be more clever to initialize the static variable outside the function instead of checking whether it was already initialized everytime the function executes.

That means my old snippet
var myFunction = function () {
    if (typeof myFunction.myStaticVar === 'undefined') {
        myFunction.myStaticVar = 0;
    }
    alert(myFunction.myStaticVar);
    myFunction.myStaticVar += 1;
};
Now becomes
var myFunction = function () {
    alert(myFunction.myStaticVar);
    myFunction.myStaticVar += 1;
};
myFunction.myStaticVar = 0;
This is far more efficient and easier to read. So thanks to Polaretto for the advice!

Another approach would be the use of a closure. We just create a new function that has the static variable in it's scope.

Let's see how this will look like:
var myFunction = (function () {
    var myStaticVar = 0;
    return function () {
        alert(myStaticVar);
        myStaticVar += 1;
    };
})();
Personally I prefer the first solution. The last one is perfectly fine and working correctly but a bit tougher to read.

February 04, 2011

Static variables in JavaScript

Update: Please also read my second part on this topic.

Per standard JavaScript does not offer the possibility of declaring a variable as static. But we can utilize the fact that in JavaScript functions are functions and objects at the same time. This means that we can put a new attribute on the function object and use it as our "static" variable.

Let's see how that works:
var myFunction = function () {
    if (typeof myFunction.myStaticVar === 'undefined') {
        myFunction.myStaticVar = 0;
    }
    alert(myFunction.myStaticVar);
    myFunction.myStaticVar += 1;
};

In line 2 we check if that object attribute we want to use as our "static variable" already exists. If not, we create and initialize it with the numeric value zero (0).

Now every time we call myFunction() we alert the current value of staticVar and afterwards increment it by 1.

The effect is, that calling
myFunction();
myFunction();
myFunction();

will open 3 alert boxes:
0
1
2

Et voilĂ ! We just emulated a static variable in JavaScript.

February 02, 2011

prototype-delegation: An event delegation framework for Prototype

Update: As Tobie mentioned in the comments there actually already exists an event delegation functionality in Prototype since version 1.7 RC 1. Have a look here for the documentation about it: http://api.prototypejs.org/dom/Element/prototype/on/

While jQuery implemented event delegation with release 1.4.2 Prototype is still lacks this feature. There are numerous workarounds for this around the web. But none of those really satisfied my needs. For a project I am currently working on we are using Prototype and were in need of event delegation for our frontend. That's why I took some time to write my own event delegation framework.

The result is prototype-delegation. Since it is a very young project I highly appreciate any feedback there.
You can find it on github.

Usage

Usage is very similar if not identical to jQuery's delegation functions.

The framework extends the Element prototype by two new methods:
delegate(selector, eventName, handler)
undelegate(selector, eventName)
delegate creates a new delegate whereas undelegate removes already installed delegations.

The expected parameters are:
  • selector is a Prototype CSS selector that identifies the element to delegate the events to
  • eventName is the name of the event you want to aggregate and delegate
  • handler is a function that gets called when the event gets delegated


Example

Now let's have a look at a short example how such an event delegation will look like with prototype-delegation:
$('myTable').delegate('tr', 'click', function () {
    alert('You clicked on: ' + this.identify());
    $('myTable').undelegate('tr', 'click');
});
In this example a table with the id 'myTable' is used as the event aggregator. It will delegate all events that match the selector "tr" - that will be every row in the table. Now everytime the user clicks into the table and that click landed on a table row element, the given callback function will get called in the context of the row element.

Inside this function we can reference the table row with the this keyword. In the example we call identify() on it which will give us the id of the row the user clicked on.

After the alert() we undelegate the click event on the tr element again which causes that we can trigger this event only once here.

That's all this framework does. There is nothing more to explain. But it still is a very powerful feature that can reduce the number of events you bind in your frontend drastically.

Links