Reputation: 339
I'm attempting to make a simple jQuery plugin to replace an element's tag in-place. Here's the source:
$.fn.replaceTag = function(tag, copyAttributes = true) {
return this.each(function() {
const newTag = tag || this.dataset.tag;
if (!newTag.length) {
return true;
}
const replacement = document.createElement(tag);
if (copyAttributes) {
for (let attr of this.attributes) {
replacement.setAttribute(attr.nodeName, attr.nodeValue);
}
}
replacement.innerHTML = this.innerHTML;
this.replaceWith(replacement);
});
};
Here's an example of its implementation:
const $xyz = $('.xyz');
setTimeout(() => $xyz.replaceTag('h1'), 2000);
setTimeout(() => $xyz.replaceTag(), 3000); /// Switch to tag defined by data-tag attribute
setTimeout(() => $xyz.replaceTag('h6', false), 5000); /// Drop attributes
Here's a demo: https://jsfiddle.net/jasongardner/cpy6e51h/
And here's the problem:
Suppose our element is <p class="xyz" data-tag="b">Hi!</p>
. I expect this example to change the initial <p>
tag to an <h1>
, then to a <b>
, and finally to an <h6>
(without any HTML attributes).
But that's not the case. The tag is replaced the first time but not replaced again in subsequent calls.
What am I missing?!
Can you recommend any plugins like this already in existence?
Thanks!
Upvotes: 1
Views: 115
Reputation: 787
It is because $xyz refers to a non existent object after the first replacement - from the documentation ( http://api.jquery.com/replacewith/ ):
The .replaceWith() method, like most jQuery methods, returns the jQuery object so that other methods can be chained onto it. However, it must be noted that the original jQuery object is returned. This object refers to the element that has been removed from the DOM, not the new element that has replaced it.
If you re-initialize $xyz before each call, it works
Upvotes: 2