When doing a .replaceWith() in jQuery the event bindings are not preserved
Asked Answered
S

4

7

Here's a condensed example.

Keep in mind that the .chat-reply class has a click event handler bound to it.

The HTML (Reply Button):

<div class="container">
    <a href="#" class="btn small chat-reply">Reply</a>
</div>

This jQuery function is called when someone clicks another button that sends a message to the server to be saved in the database. This is done via ajax and is done successfully. In the aforementioned .ajax() success() callback this function is called:

$.ajax({
      type      :  'GET',
      url       :  '/some_controller/some_method',
      success   :  function(data) {

      $('.container').replaceWith(data);
    }
});

The 'data' in the success callback above will replace the entire .container div including the child .chat-reply button. After this replaceWith(), the click event is no longer bound to the button.

Logically, I'm attempting to have the end user post a message to a timeline, then have that message display in the timeline without needing to refresh the screen.

Spavined answered 14/2, 2012 at 3:8 Comment(0)
S
1

Decided on a rather not-so-elegant solution thanks in part to this post: Events not registering after replaceWith

I created a function called wireUpChatReply() that binds a click event to the .chat-reply button.

Then after the replaceWith(), I make a call to wireUpChatReply() to rebind the events. I make this same call to wireUpChatReply on document.ready.

It's not pretty but it works.

Spavined answered 14/2, 2012 at 3:56 Comment(0)
B
3

Grab jquery 1.7 that now uses 'on' to bind: http://blog.jquery.com/2011/09/28/jquery-1-7-beta-1-released/

Or if < 1.7 use 'live' instead of 'bind' as it will look for DOM changes and re-apply the events of changed content. If not you can reapply the event on your callback.

Old api to replacement to bind with live type event handlers after DOM changes.

this $(selector).live(events, fn)

becomes this $(document).on(events, selector, fn)

Or in code

This

$(".container a.chat-reply").live("click", function(){
 // do it live!
});

Becomes this in 1.7

$(".container").on("click", "a.chat-reply", function(event){
 // do it live!
});

With various options to selecting the object you want.

Berezina answered 14/2, 2012 at 3:12 Comment(2)
Your code example is a little confusing to me. If you don't mind clarifying a little, that would be great.Spavined
Sry the block was just pointing from old 'live' to 'on' but Vigrond's example is how you do an 'on'. It would almost be better to attach the event after the html is received in your callback.Berezina
K
2

In your click handler, use .on() as a delegate instead

$("div.container").on("click", "a.chat-reply", function(even){
  //click handler here
});

the event will 'bubble' up to container, and if it matches a.chat-replay it will trigger.

Kokura answered 14/2, 2012 at 3:13 Comment(7)
The "bubbling up" worked however once I do a replaceWith(), those event bindings are gone--still.Spavined
of course. my bad, replaceWith will replace the entire element. Is it possible for you to do .html(content) instead? That will replace its content, not the .container element. Otherwise you'll have to start looking at the ancestors of .container to attach the .on event handler to.Kokura
Ewww. That can get nasty. I found another post that suggested having a function that "wires-up" the event binding. Then calling it again AFTER the replaceWith(). It's not pretty but I might not have much of a choice.Spavined
Furthermore, I thought about the .html(content) approach but it's just too much other stuff going on, on the back end to make this approach efficient.Spavined
Here's a link to the similar question: #770808Spavined
Ok, it's hard to give you an accurate answer if you don't details.Kokura
I understand. And I appreciate your help. I condensed the example down to focus more on the most important aspect. What's returned from the .ajax call (i.e. the data variable), I felt was irrelevant because I'm not at the point where I would consider changing the data returned from my controller. I hope that makes sense.Spavined
S
1

Decided on a rather not-so-elegant solution thanks in part to this post: Events not registering after replaceWith

I created a function called wireUpChatReply() that binds a click event to the .chat-reply button.

Then after the replaceWith(), I make a call to wireUpChatReply() to rebind the events. I make this same call to wireUpChatReply on document.ready.

It's not pretty but it works.

Spavined answered 14/2, 2012 at 3:56 Comment(0)
W
0

The two answers regarding live events do not fix the problem, because the container itself is replaced and the event binding is gone.

Instead of rebinding the events, in which case you need to know the already bound events, you can do the following:

$(".container").parent().on("click", ".container a.chat-reply", function(){
  // do something
});

or, if there are several containers:

$(document.body).on("click", ".container a.chat-reply", function(){
  // do something
});
Wherry answered 11/1, 2018 at 13:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.