简体   繁体   中英

Event fails to fire after DOM change in jQuery 1.9

I am trying to code a cancel button for user input. The user will be able to edit an item after double-clicking on it and the cancel button will allow the user to cancel the action.

The double-clicking part of the code works great, as a text-input box appears with cancel button attached. But now since the DOM has changed, jQuery no longer select the new element, and therefore when the cancel button is clicked the event is not fired. To illustrate, the code are following:

<div id="main">
<ul class="todoList">
    <li id="todo-1" class="todo">
        <div class="text">New Todo Item. Doubleclick to Edit
         </div>
        <div class="actions"> <a href="#" class="edit">Edit</a></div>
    </li>
</ul>
</div>

var currentTODO;
$('.todo').on('dblclick', function () {
    $(this).find('a.edit').click();
});

$('.todo a').on('click', function (e) {
    e.preventDefault();
    currentTODO = $(this).closest('.todo');
});

$('.todo a.edit').on('click', function () {

    var container = currentTODO.find('.text');

    if (!currentTODO.data('origText')) {
        // Saving the current value of the ToDo so we can
        // restore it later if the user discards the changes:

        currentTODO.data('origText', container.text());
    } else {
        // This will block the edit button if the edit box is already open:
        return false;
    }

    $('<input type="text">').val(container.text()).appendTo(container.empty());

    container.append(
        '<div class="editTodo">' +
        '<a class="cancel" href="#">Cancel</a>' +
        '</div>');

});

// The cancel edit link:

$('.cancel').on('click', function () {
    alert("oops");
});

Or here: http://jsfiddle.net/S7f83/42/

My question is therefore, how can I 'bind' the event after DOM has changed? Thank you very much

In your example the events are bound to the controls which exist at the moment of binding, and match the selector. If you would like the actions to apply for newly created controls, you shall bind the event to the document itself. As it is the highest level DOM element, all the events from lower levels will propagate up to it.

At the second parameter you give the context, so only if the event is received from that context will the function fire.

$(document).on('dblclick', '.todo', function () {
    $(this).find('a.edit').click();
});

I won't cite your whole code, but you will get the idea from this one.

Binding listeners to the document is encouraged as it doesn't create as many bindings as many controls you have, just one top level binding, which waits for events to propagate up on the DOM tree. More info on optimalization: http://24ways.org/2011/your-jquery-now-with-less-suck/

Use

$('.todo').on('click', '.cancel', function () {
    alert("oops");
});

so you delegate the event to an existing element ( the .todo )

instead of

$('.cancel').on('click', function () {
    alert("oops");
});

2 Methods

In the 2nd case, I bind the event delegation to the nearest parent, so the event doesn't need to bubble to the document element to be executed. This could improve some performance. It depends on the use whether you want to place the cancel button anywhere else or not.

EDIT: each li has a different id, so it's better to attach to the class .todo

$('.todo').on('click', 'a.cancel', function () { alert("oops"); });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM