3

I was just tried to answer this question. Actually the op has asked that the event not getting fired on a cloned element. while looking at his code, he had used .clone() function to accomplish his task,

so what i suggested was to use .clone(true). The doc says that if we pass the first argument as true in .clone() function, then the cloned copy would retain the data and their event handlers. But it is not behaving like so. Am i misunderstanding anything.. can any body guide me in the right direction..?

DEMO

Code taken from the fiddle,

$('button').on('click', function(){
  $(this).replaceWith('<p>'+ $(this).text() +'</p>');
  $(this).clone(true).appendTo('body');
});
Community
  • 1
  • 1
Rajaprabhu Aravindasamy
  • 66,513
  • 17
  • 101
  • 130

3 Answers3

7

If you invert .replaceWith() with .clone() it'll work:

$('button').on('click', function(){
  $(this).clone(true).appendTo('body');
  $(this).replaceWith('<p>'+ $(this).text() +'</p>');
});

The .replaceWith() will clear all the events bound to the element (as discussed here). When you call .clone() after that, there's no events to retain.

My guess is that .clone() retains the base html even before the call to it (like in a internal variable) and .clone(true) retrieves that value and then bind the events.

Community
  • 1
  • 1
Denis Ali
  • 1,062
  • 7
  • 8
  • 1
    This is the answer. replaceWith removes the events on the element (could be a bug, could be not, it's been discussed and they're leaving it as-is because it's supposedly 'rare'. Refer to: http://bugs.jquery.com/ticket/13400). But for the record, clone doesn't "retain the base html". The "this" variable that is in scope is simply a pointer to the dom node. When you call .replaceWith, it swaps the node (i.e. its position w.r.t its parent) for the new node created. – sahbeewah May 16 '14 at 05:14
  • The semantics and purpose of `button` and a `div` are pretty different, so if anything this is a good example of why it's inappropriate for jQuery to copy events and data over as standard procedure. The goal of `replaceWith` is to put something in the same place in the DOM, but the elements don't swap uniforms or anything like that. – Dave Methvin May 16 '14 at 17:50
2

I think the problem comes from the on method (have a look to the last example). The following code is working :

$(document).on('click', 'button', function(){
  $(this).replaceWith('<p>'+ $(this).text() +'</p>');
  $(this).clone(true).appendTo('body');
});

I edited the jsfiddle : http://jsfiddle.net/bk5tF/5/

Lucas Willems
  • 6,673
  • 4
  • 28
  • 45
  • why should we use `event-delegation` here while the events are getting retained..? – Rajaprabhu Aravindasamy May 13 '14 at 06:55
  • @RajaprabhuAravindasamy Please read the section "[Direct and delegated events](http://api.jquery.com/on/)" from the docs. – Thorsten May 15 '14 at 13:11
  • @lucas-willems you changed the $('button').on('click', function(){.... to $(document).on('click', 'button', function(){.... can you explain in detail why the first one doesn't work and the second one works? din't understand the reason and logic behind it – Chetan Nov 07 '17 at 14:59
  • @Chetan The first handler looks for events on the button, which will be replaced. The second handler looks at events on the document, which are bubbled up from a button, no matter what button it is. For further reading take a look here: http://api.jquery.com/on/#direct-and-delegated-events – RiZKiT Jan 11 '18 at 13:24
1

Elements, which are added later does not respond to any event handler attached to them. For example in your case, you added a click event for buttons. That is clicking on them will replace them with <p> and will append its clone at bottom of body. But as this newly appended button was not there when DOM was loaded, it will not respond to the previously defined click event.

Now to make them respond with click event, even if they are appended later in DOM, you need to use either live or delegate to attach an event handler to your button elements. However live is deprecated now, so delegate should be used. That way newly added elements will respond to your click event.

Check out this code and fiddle -

$('body').delegate('button', 'click', function(){
  $(this).replaceWith('<p>'+ $(this).text() +'</p>');
  $(this).clone().appendTo('body');
});
abir_maiti
  • 490
  • 3
  • 9