Search code examples
jqueryclone

replaceWith() not working on cloned, detached nodes


replaceWith() is not working properly for me. For example, given this HTML:

<div id="tree1">
    <div>
        <h3>Item 1</h3>
        <h3>Item 2</h3>
        <h3>Item 3</h3>
    </div>
</div>

this code does not replace the <h3> nodes with <li>s:

var items_Bad   = $("#tree1 div h3").clone ();

$("#tree1 div").remove ();
$("#tree1").append ('<ul id="Items1"></ul>');

//--- This does not replace anything!
items_Bad.replaceWith (function () {
    return ('<li>' + $(this).text () + '</li>');
} );

$("#Items1").append (items_Bad);


But this code does! :

var items_Good  = $("#tree1 div h3").clone ();

$("#tree1 div").remove ();
$("#tree1").append ('<ul id="Items1"></ul>');

$("#Items1").append (items_Good);

//--- But, this works!
$("#Items1 h3"). replaceWith (function () {
    return ('<li>' + $(this).text () + '</li>');
} );


See the jsFiddle.

Here, replaceWith() works only if the nodes are (re)attached to the DOM, but the documentation says that:

As of jQuery 1.4, .replaceWith() can also work on disconnected DOM nodes.

What am I missing?

(Note that I don't control the original page's source. And, I have a lot more manipulation to do, so reattaching the nodes prematurely to manipulate them is undesirable.)


Solution

  • The code below is the part of replaceWith() that deals with replacing detached nodes (taken straight from the jQuery 1.7.1 source, modulo minor formatting differences):

    replaceWith: function(value) {
        if (this[0] && this[0].parentNode) {
            // This deals with attached nodes...
        } else {
            return this.length
                ? this.pushStack(jQuery(jQuery.isFunction(value) ? value() : value),
                    "replaceWith", value)
                : this;
        }
    }
    

    As you can see, there are two limitations that prevent this code from fulfilling your requirements:

    • The supplied function is only called once instead of once per element in the set,
    • The supplied function is called in the global context (i.e. the element being replaced is not available through the this keyword).

    So, I'm afraid replacing detached nodes is still a work in progress, and you will have to fall back to your second solution until the limitations above are fixed.