0

I have the following code :

$('div[class^=locked_]').click(function() {
        var newThis = $(this) ;
        $(this).load(url + " #" + $(this).attr("id"), function() {
            var loaded = $(this).children("#" + $(this).attr("id")) ;
            alert($(loaded).attr("class")) ; // displays "locked_true"
            $(newThis).replaceWith($(loaded)) ;
            alert($(newThis).html()) ;

        }) ;
    }) ;

I don't understand the behaviour I get : the first alert displays the right class (beginning with "locked_"). The second alert displays null. I cannot click again on the same button although it has the right class. Is it normal? What should I do ?

Adrien Gorrell
  • 1,291
  • 3
  • 14
  • 28
  • 3
    You are `$`-wrapping your `newThis` twice (it already *is* a jQuery object), but that should not be the initial cause of your problem I guess. – m90 Aug 07 '12 at 14:32
  • What is your code supposed to be doing? do you even need ANY of the code within the callback of .load? it all looks redundant. – Kevin B Aug 07 '12 at 14:40
  • I'm pretty sure JQ handles further attempts at wrapping well. I know because I did it a lot back when I had no clue what JQ was doing. – Erik Reppen Aug 07 '12 at 14:46

2 Answers2

6

Event handlers (except delegated events - more on this later) are bound directly to the element. If you replace that element - which is precisely what you do when you use the .replaceWith() function - you're removing that event handler along with the element; you won't get your event bound to the new element.

The solution, as mentioned earlier, is event delegation. The general principle is that you set up an event handler on a static element that will contain your dynamic elements, which will handle the event and be responsible for executing the callback function when the target of the event matches the selector provided.

If you're using jQuery 1.7+, you can use the .on() function to do this:

$(document).on('click', 'div[class^=locked_]', function(e) {
    var newThis = $(this) ;
    $(this).load(url + " #" + $(this).attr("id"), function() {
        var loaded = $(this).children("#" + $(this).attr("id")) ;
        alert($(loaded).attr("class")) ; // displays "locked_true"
        $(newThis).replaceWith($(loaded)) ;
        alert($(newThis).html()) ;
    });
});

I've used document in the example, but ideally you'd go for a more specific static element (the closer to your dynamic elements the better).

If you're not using jQuery 1.7+, you can get the same functionality using the .delegate() function - the syntax is practically the same, you just switch the 'click' and 'div[class^=locked_]' arguments.

Anthony Grist
  • 38,173
  • 8
  • 62
  • 76
  • Thanks a lot ! As a matter of fact, I didn't have the right version of JQuery to use on(), so thanks for the detail on versions. – Adrien Gorrell Aug 07 '12 at 15:02
  • So now, it works. I can click over and over again. However the alert(newThis.html()) displays an empty string. – Adrien Gorrell Aug 07 '12 at 15:09
  • 1
    @user1360941 Any reference to `newThis` in the code after that `.replaceWith()` call is going to be referring to an element that no longer exists, so not entirely surprising that it returns an empty string. – Anthony Grist Aug 07 '12 at 15:48
3

replaceWith removes an element from the DOM and replaces it with another. Your newThis is referencing the old element, which was just removed from the DOM.

gen_Eric
  • 223,194
  • 41
  • 299
  • 337