Question

I seem to have an issue when creating copies of a template and tying the .click() method to them properly. Take the following javascript for example:

function TestMethod() {
    var test = Array();
    test[0] = 0;
    test[1] = 1;
    test[2] = 2;

    // Insert link into the page
    $("#test_div").html("<a href=\"#\"></a><br>");
    var list;
    for (x = 0; x < test.length; x++) {
        var temp = $("#test_div").clone();
        temp.find('a').html("Item #" + test[x]);
        temp.click(function () { alert(x); });

        if (list == undefined)
            list = temp;
        else
            list = list.append(temp.contents());
    }
    $("#test_div2").append(list);
 }

The problem I am seeing with this is that no matter which item the user clicks on, it always runs alert(2), even when you click on the first few items.

How can I get this to work?

Edit: I have made a very simple example that should show the problem much clearer. No matter what item you click on, it always shows an alert box with the number 2 on it.

Was it helpful?

Solution

Correct me if I'm wrong, .valueOf() in JS returns the primitive value of a Boolean object.....

this would not happen ShowObject(5,'T');... ShowObject(objectVal.valueOf(), 'T');

why not use objects[x].Value directly? ShowObject(objects[x].Value, 'T');

WOOOOOSSSHHHH!

after searching deeply... I found a solution...

because it's a closure, it won't really work that way...
here's a solution,

temp.find('a').bind('click', {testVal: x},function (e) { 
   alert(e.data.testVal);
   return false;
});

for best explanation, please read this... in the middle part of the page where it says Passing Event Data
a quick demo of above code

OTHER TIPS

I think your issue arises from a misunderstanding of scopes in JavaScript. (My apologies if I'm wrong.)

function () {
    for (...) {
        var foo = ...;

        $('<div>').click(function () { alert(foo); }).appendTo(...);
    }
}

In JavaScript, only functions create a new scope (commonly referred to as a closure).

So, every round of the for loop will know the same foo, since its scope is the function, not the for. This also applies to the events being defined. By the end of looping, every click will know the same foo and know it to be the last value it was assigned.

To get around this, either create an inner closure with an immediately-executing, anonymous function:

function () {
    for (...) {
        (function (foo) {
            $('<div>').click(function () { alert(foo); }).appendTo(...);
        })(...);
    }
}

Or, using a callback-based function, such as jQuery.each:

function () {
    $.each(..., function (i, foo) {
        $('<div>').click(function () { alert(foo); }).appendTo(...);
    });
}

For your issue, I'd go with the latter (note the changes of objects[x] to just object):

var list;
jQuery.each(data.objects, function (x, object) {

    // Clone the object list item template
    var item = $("#object_item_list_template").clone();

    // Setup the click action and inner text for the link tag in the template
    var objectVal = object.Value;
    item.find('a').click(function () { ShowObject(objectVal.valueOf(), 'T'); }).html(object.Text);

    // add the html to the list
    if (list == undefined)
        list = item;
    else
        list.append(item.contents());
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top