views:

57

answers:

2

I'm looking at transferring existing functionality (built with PrototypeJS) to jQuery and have been working through a couple of examples.

One example I'm a bit stuck on, specifically with regards to binding functions (and values) to an event. This example tries to apply a mouseover event, with an incremented value to a list of links. The value that is alerted I want to be the same every time (so link 1 alerts "1", link 2 alert "2" etc etc)

Here's a snippet of a simple example.

Prototype:

findLinks: function () {
    i = 1;

    $$("#vertical-content-links ul li a").each(function (s) {
        Event.observe(s, "mouseover", this.activateLink.bindAsEventListener(this, i))
        i++
    }.bind(this))
},

activateLink: function (e, i) {
    alert(i)
}

Within this example, when link 1 is mouseovered, it will always alert "1". Link 2 will always alert "2" etc etc as it is alerting the value of i when the function is applied to that event.

However, my similar code in jQuery....

findLinks: function () {
    i = 1;

    $("#vertical-content-links ul li a").each(function (s, elmt) {
        $(elmt).bind("mouseover", function (e) {
            _this.activateLink(i);
            i++
        })
    })
},


activateLink: function (i) {
   alert(i);
}

(Note: _this is a closure specified elsewhere in the code)

When this runs, every time a link is mouseovered, the value of i is incremented by one, so link 1 will alert 1, then 2,3,4,5 etc as the value of i doesn't seem to be bound to the function when it is applied to the event

Hope that makes sense

Does anyone know a way around this so it works more the way Prototype does. I really want to start using jQuery more but need to understand this issue first.

Cheers

A: 

I bet that i gets incremented because you put i++ inside the mouseover handler. Carry it out and try this:

findLinks: function() {
    var i = 1;
    $("#vertical-content-links ul li a").each(function(s, elmt) {
        var j = i++;
        $(elmt).bind("mouseover",function(e) {
            _this.activateLink(j);
        })
    })
},
Igor Zinov'yev
This doesn't work either - it just alerts out the value after all the incrementations of i have occurred.i++ within my PrototypeJS example works within the event handler because the function and it's variables values (including i) are written to the event once. Every mouseover runs the function applied to that event (including original values).jQuery looks like its returning the function each time the event is triggered eg: findLinks(), rather than running the function that is applied to the event eg: findLinks (without the brackets).
Starls
Yes, sorry, I fixed it. It should work now.
Igor Zinov'yev
Great - this works well too. Thanks
Starls
@Starls - There's really no reason for your own variable or incrementing it here, it's extra code/waste...if you're using a library, use what's built in for you...
Nick Craver
@Nick, Yes, in this case there is no reason to use another variable, but there could be a case where you want to set different values of `j` depending on `s` s value. What's useless here is `i` and incrementing, you're right on that.
Igor Zinov'yev
+1  A: 

.each() already forms a closure here, so just use the iterator it already has, your s variable, like this:

$("#vertical-content-links ul li a").each(function (s, elmt) {
    $(elmt).bind("mouseover", function (e) { //or just .mouseover(function() {
        _this.activateLink(s+1);             //0-based index, so add 1
    });
});

Try out a demo here. The first argument of the .each() callback function is the index of the element in the matches set, and since it's passed into the closure you don't have to worry about referencing the same changing i variable like you currently have.

Nick Craver
Thanks Nick - that works!I think I did have that option in the back of my mind, but I'm a bit stuck in my ways with how I use Prototype and wanted to replicate those techniques more.This is a good solution though - Thanks!
Starls
@Starls - Welcome :) Usually there's an equally short or much *more* concise way to write it in jQuery in my experience. The `.bind()` isn't *exactly* the same as prototype, which allows the parameter stuffing and such, just a different way of thinking I suppose...but if you run into issues just ask here, you'll find no shortage of help. Also remember to accept answers on this and future questions via the check-mark beside the one that resolved your issue best :)
Nick Craver