0

Using jQuery, I get HTML data with the $.get() function. In callback function, when I put a breakpoint, the data variable is not empty and I see my link with the proper class (deleteLink), so I can select it.

$.get(path, function(data) {
    $(data).find("a.deleteLink").click(function(event) {
        event.preventDefault();
        DeleteRow(event);
    });
    $("#tbody_id").append(data);
});

Example of data received:

<tr>
    <td>Some data</td>
    <td><a href="#" class="deleteLink">X</a></td>
</tr>

I've tried to append() data after and before assigning the event listener to the link. Having no JS error when I receive data, having the good element returned with $(data).find("a.deleteLink") function, having also the correct <tbody> element returned by $("#tbody_id"), and no error when I click on link, why DeleteRow() is never called?

sgy
  • 2,922
  • 2
  • 35
  • 42
  • 1
    When you append before assigning the click handler, do you assign the handler within `data` or do you identify the element from where it was appended in the DOM? I suspect the latter will work better than the former. Either way, using event delegation with `on()` would make this a lot easier. – David Jul 28 '14 at 19:08
  • @David is correct, using the on() delegation is what yo want here. – Mark Jul 28 '14 at 19:10

4 Answers4

1

I assume when you swap the order of events, it looks like this:

$("#tbody_id").append(data);
$(data).find("a.deleteLink").click(function(event) {
    event.preventDefault();
    DeleteRow(event);
});

I suspect the problem here is that data isn't part of the DOM, so you're not actually appending any click handlers to DOM elements. Contrast the above with this:

$("#tbody_id").append(data);
$("#tbody_id").find("a.deleteLink").click(function(event) {
    event.preventDefault();
    DeleteRow(event);
});

In this case the second statement is looking in the DOM, not in a string returned from the server. It's a subtle but important difference.

Either way, you can accomplish this a lot easier by using event delegation. Simply bind the click event to a common non-dynamic parent element and filter by event-originating elements:

$("#tbody_id").on("click", "a.deleteLink", function(event) {
    event.preventDefault();
    DeleteRow(event);
});

This would be outside your AJAX call, it just needs to be bound once. Then inside your AJAX call all you'd have to do is append:

$.get(path, function(data) {
    $("#tbody_id").append(data);
});
David
  • 208,112
  • 36
  • 198
  • 279
1

Like David mentioned in the comments, it's much easier to define the event handler using on(). With this, you can create a delegated event handler. From jQuery's documentation reference:

Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. By picking an element that is guaranteed to be present at the time the delegated event handler is attached, you can use delegated events to avoid the need to frequently attach and remove event handlers.

Therefore, pick a parent element that exists and you only need to bind the event once.

$('#tbody_id').on('click', '.deleteLink', function(event) {
  event.preventDefault();
  DeleteRow(event);
});

$.get(path, function(data) {
  $("#tbody_id").append(data);
});
Brett
  • 4,268
  • 1
  • 13
  • 28
0

When you do $(data) initially, jQuery creates elements out of your raw HTML, and then you add your event handler to an element in that. But then when you .append(data) it makes NEW elements out of the HTML, unrelated to the elements you created first and added an event handler to. What you could do is process it into DOM elements once, add the event handler to that, and then append that:

$.get(path, function(data) {
    var $el = $(data);
    $el.find("a.deleteLink").click(function(event) {
        event.preventDefault();
        DeleteRow(event);
    });
    $("#tbody_id").append($el);
});
crimson_penguin
  • 2,728
  • 1
  • 17
  • 24
0

You are finding the links inside data before it has been added to the DOM, i'm not sure you can do that.

Append the data first and then attach the onlick event:

$.get(path, function(data) {
    $("#tbody_id").append(data);
    $("a.deleteLink").click(function(event) {
        event.preventDefault();
        DeleteRow(event);
    });        
});

You could also just do a delegate click event that would always find your generated content:

$("#tbody_id").on("click", "a.deleteLink", function(){
    event.preventDefault();
    DeleteRow(event);
});

Then you don't have to add a new event each time you fetch data. Hope that helps

Brunis
  • 1,073
  • 8
  • 12