scriptNode

Web development with a focus on JavaScript RSS

Welcome to scriptNode: articles, tutorials and news about web development. Learn more…

The “Last in a Loop” Bug

Intermediate Matt Hackett Published August 28th, 2008 by Matt Hackett

The Problem

If you've had your hands in JavaScript for a while, chances are you've ran into this bug. You've got a bunch of elements you're either adding to the DOM or a bunch of listeners you're attaching to elements. Either way, you keep getting the same result: the last value in the loop. Here's an example:

Let's say you've got a list of 5 items and you want to listen to the click event for each. Many developers would immediately think of doing it this way:

You can try this example below:

  • Item #1 - click me!
  • Item #2 - click me!
  • Item #3 - click me!
  • Item #4 - click me!
  • Item #5 - click me!

No matter which element is clicked, the same result keeps appearing: You clicked element #5. This baffles many JavaScript programmers. So what's going on here?

The issue here is a misunderstanding of closure. In the above example, it's assumed that the variable i will retain its value during the loop for that particular function call. But actually what's happening is the click function is accessing the same i variable that the for loop accessed. So anytime i is checked, its value will be the same as it was when the loop finished.

A Solution

Usually what a developer wants to accomplish is a function listening to the click event that retains the value of i as it was during that iteration in the loop. Here's a way to accomplish that behavior:

This pattern can be more than a little confusing. Let's walk through it line-by-line, starting with line 5:

  1. This time we're firing off a function immediately, allowing us to run some code within a closure to avoid i changing values on us.
  2. We still want the onclick to be assigned a function to fire, so we return an anonymous function just like we did before.
  3. We alert the item number just like we normally would (but this time it will work).
  4. End the returned function.
  5. End the onclick assignment. This function gets fired off immediately because of the parentheses. We pass i in, retaining its current loop value because of the function scope we declared on line 5. This is probably the step that confuses developers the most.

Here is that example in action:

  • Item #1 - click me!
  • Item #2 - click me!
  • Item #3 - click me!
  • Item #4 - click me!
  • Item #5 - click me!

And it works the way you'd expect! What do you think? If you don't quite understand the pattern, or have another method to use to solve this problem, I'd love to hear about it in the comments.

Read other articles tagged: ,

MySQL Database Class

Intermediate Matt Hackett Published August 24th, 2008 by Matt Hackett

I've been spending loads of time recently with a new project that's supposed to be comprised mostly of what I love doing the most: hardcore JavaScript. Unfortunately, most front-ends aren't much without a back-end to fall on, so I've had to hit the PHP pretty hard too.

When modifying the framework I had built, I noticed that the old database class I was using was a little out of date. PHP5 is the new standard, shouldn't we all be using PDO? So I added migrating to PDO to my to-do list. But really, the class is a pretty good one. It's certainly been useful to me for, well, almost a few years now, give or take a few dozen tweaks.

So given the longevity of the script, I thought I'd offer it up for this week's Script Sunday:

And here's a quick example of how to use it:

Read other articles tagged: , ,

Quickly Update DocumentRoot in Apache2

Intermediate Matt Hackett Published August 10th, 2008 by Matt Hackett

For today's Script Sunday I thought I'd take a go back in time a little and provide an old utility that I still to this day find useful. It's a script I wrote called ChangeLocalHost which alters the DocumentRoot in apache2. An example of its use would be:

./clh.php local-site.com/public_html/

Note: you must be root to run it

Given this command, the script will change DocumentRoot to local-site.com/public_html/ and restart apache2. I work on a lot of websites (developing most of them on my laptop running apache2) so I use this script constantly.

Here's the code:

You'll notice that the script is at least a year and a half old. Usually if code of mine is more than a year old, it's completely unusuable because my habits change pretty often. But I think I've finally gotten to that sweet spot where it's not total garbage, it just needs tweaking.

I was surprised that the code isn't too bad really. It's easily readable and well organized. There are many things that I wouldn't have done were I to write this again; for example, I stopped using type prefixes long ago (such as an array of users as $arr_users). I understand why I used to do this, but it's not necessary and only clutters up the code.

Anyway, I find this script useful and I thought someone else might too. Enjoy!

Read other articles tagged: , , , ,
© 2008 scriptNode