1

There are a few questions that ask about changing an element to one of another type, preserving attributes, using jQuery. .replaceWith() does the trick, and that's what this plugin uses. But dropping the original element from the DOM drops its event handlers with it. How would one go about replacing an element and transferring any bound handlers to the new element?

Specifically, I'm replacing an <input type="text"> with a <select>. I'm using jQuery 1.10.

Sam Kauffman
  • 1,221
  • 11
  • 30
  • I'm thinking something involving `$._data`. [More info](http://stackoverflow.com/a/2008622/1248084) –  Jan 20 '15 at 23:02
  • 1
    The info you are looking for is likely here: http://bugs.jquery.com/ticket/13400 – doublesharp Jan 20 '15 at 23:05

3 Answers3

3

Try attaching event to $(document) , adding unique class to replaced, replacement elements

$(document).on("change", ".toggle", function(e) {
  console.log(e.target.value)
});

Replace input.toggle element with select.toggle element; cache new .toggle element as selector; remove input.toggle DOM element, jQuery object

// replace `input` element with `select` element, having same unique `class`
// create cached selector of replacement `select` element, `toggled`
// remove jQuery object, `DOM` element `input.toggle`
var toggled = $(".toggle").replaceWith(function(i, el) {
                  return "<select class=toggle name=toggle>"
                         + "<option value=null>1</option>"
                         + "<option value=2>2</option>"
                         + "</select>"
                  }) && $(".toggle").is("input") || $("select.toggle");
$("input.toggle").remove();

$(document).on("change", ".toggle", function(e) {
  console.log(e.target.value)
});

$(".toggle").val("input").change();

setTimeout(function() {
var toggled = $(".toggle").replaceWith(function(i, el) {
  return "<select class=toggle name=toggle><option value=null>1</option><option value=2>2</option></select>"
}) && $(".toggle").is("input") || $("select.toggle");
  $("input.toggle").remove();
  toggled.find("option:first").val("select").change();
}, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<input class="toggle" name="toggle" type="text" value="" />
guest271314
  • 1
  • 15
  • 104
  • 177
3

I found another question that seems to answer what you're trying to do

Duplicate one element's event handlers onto another?

They do the following

$.each($._data($('#original').get(0), 'events'), function() {
  // iterate registered handler of original
  $.each(this, function() {
    $('#target').bind(this.type, this.handler);
  });
});

Accessing the $._data of the original element $('#original') allows you to gain access to the events it has attached, so iterating over each one allows you to attach the same events to a new element, in this case $('#target')

Community
  • 1
  • 1
sbonkosky
  • 2,537
  • 1
  • 22
  • 31
0

The replaceWith() method will lose the events, however you can use the following code in place of it to keep the attached events.

// using replaceWith()
old.replaceWith( new );

// use detach() to keep the events
old.before( new ).detach();
doublesharp
  • 26,888
  • 6
  • 52
  • 73
  • This snippet solves the slightly different problem of keeping the handlers on the old element, which will be re-inserted later. I want to transfer them to the new element. – Sam Kauffman Jan 21 '15 at 16:42