Sunday, June 05, 2011

BYBS: Stupid JavaScript Tricks

This week I learned something about working with JavaScript that made me happy enough that I'm going to blog about it.

Rather than trying to explain this in some way that makes sense, I'm going to use the short version.  This will not confuse any readers because a) I don't have any and b) anyone who stumbles upon this blog must already be a JavaScript gawd.

OK, so suppose you are using Ajax to grab a list of people and you want to shove them in a table, along with a button that initiates some action that annoys said person.  Well, one way that might seem plausible is to use the following:

var button = document.createElement("input");
button.type = "button";
button.value="Annoy";
button.onclick = "annoyPerson(person.id)";

Unfortunately, this does not work, since JavaScript really wants to get a function for Christmas when you pass it the value for onclick.  OK, how about this:

button.onclick = function (id) {
    annoyPerson(id);
};

This doesn't work either because onclick will not pass any parameters to the function it calls.  So how about:

button.onclick = function() {
    annoyPerson(person.id);
};

This sort of works, in that it will call annoyPerson with an ID that is taken from the list that you are iterating over, but it will be the same value for all the buttons.  This means that you might click the button to annoy Fred only to annoy Mary instead.  Very embarrassing.

OK, so how do you pass in the correct ID?  There are two ways that I found out about.  Probably the preferred way is to use the following:

button.setAttribute("data-person-id", person.id);
button.onclick = function() {
    annoyPerson(this.getAttribute("data-person-id"));
};

The way that I thought was especially kewl, however, was the following:

button.onclick = function(id) {
    return function() {
        annoyPerson(id);
    }
}(person.id);

This wonky mess of JavaScript defines an "anonymous" function that returns another function.  The outer anonymous function is then immediately called (via the (person.id) bit at the end).  This binds the current value for person.id to the id parameter, ensuring that the inner anonymous function gets a different value for each iteration of the loop, rather than the last value the iterator held.

If this seems long-winded and impossible to follow, it's because it is actually long-winded and impossible to follow.  JavaScript is a strange and annoying language in my not-so humble opinion, and it often times feels like voodoo when you get something to actually work.

Nevertheless, getting this to work was a nice point in my week.  Which just gives people another indication of how pathetic my life is.

No comments: