Привязка кликов Jquery не работает правильно при связывании нескольких копий - PullRequest
2 голосов
/ 14 мая 2010

Кажется, у меня проблема при создании копий шаблона и правильной привязке к ним метода .click (). Возьмите следующий javascript для примера:

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);
 }

Проблема, с которой я сталкиваюсь, заключается в том, что независимо от того, на каком элементе нажимает пользователь, он всегда запускает alert (2), даже когда вы нажимаете на первые несколько элементов.

Как мне заставить это работать?

Редактировать: Я сделал очень простой пример, который должен показать проблему намного яснее. Независимо от того, на каком объекте вы щелкаете, на нем всегда отображается окно с номером 2.

Ответы [ 2 ]

1 голос
/ 14 мая 2010

Я думаю, что ваша проблема возникает из-за неправильного понимания областей действия в JavaScript. (Мои извинения, если я ошибаюсь.)

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

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

В JavaScript только функции создают новую область действия (обычно называемую closure ).

Таким образом, каждый раунд цикла for будет знать один и тот же foo, поскольку его область действия - function, а не for. Это также относится к определяемым событиям. К концу цикла каждый click будет знать тот же foo и будет знать, что это последнее значение, которое ему было присвоено.

Чтобы обойти это, создайте внутреннее закрытие с помощью немедленно выполняющейся анонимной функции:

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

Или, используя функцию обратного вызова, такую ​​как jQuery.each:

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

Для вашей проблемы, я бы пошел с последним (обратите внимание на изменения objects[x] до просто 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());
});
1 голос
/ 14 мая 2010

Поправьте меня, если я ошибаюсь, .valueOf() в JS возвращает примитивное значение логического объекта .....

этого бы не случилось ShowObject(5,'T'); ... ShowObject(objectVal.valueOf(), 'T');

почему бы не использовать objects[x].Value напрямую? ShowObject(objects[x].Value, 'T');

WOOOOOSSSHHHH!

после глубокого поиска ... я нашел решение ...

потому что это закрытие, на самом деле это не сработает ...
вот решение,

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

для лучшего объяснения, прочитайте это ... в средней части страницы, где написано Передача данных события
быстрое демо вышеуказанного кода

...