Ever have a tag or DOM Node in Javascript and go "hmm.. I just really need that to like be in a <span>
now...". Me too. We "wrap" and "unwrap" tags a lot in our projects so I decided to write three simple utilities that can help with that.
wrap
// wrap an element with another; super basic but makes it consistent across our apps
function wrap(el, wrapper) {
if (el && el.parentNode) {
el.parentNode.insertBefore(wrapper, el);
wrapper.appendChild(el);
}
}
How it works
wrap()
works by taking in a DOM node as el
, the thing you want to wrap as well as a wrapper
element. Think of the wrapper element as a <strong>
, <span>
, <div>
or whatever you need to wrap something in. Then think of the el
tag as the thing that you need to put inside that <strong>
tag.
The function verifies that this is an element and that it has a parentNode. In JS we need to know that the element we're about to do things to has a parent, otherwise we don't know where to place something. Because the DOM is a tree structure, we can't interact with a child's placement in the page unless we know who it's parent is.
As a sentence we get code spoken like this: "Take the element to wrap, go to it's parent, then insert the wrapper juuuust before the element." This means that for a split instant we have
<parent-tag>
<wrapper-tag></wrapper-tag>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
</parent-tag>
Lastly, we take the tag we need to wrap and run appendChild
to insert it into the wrapper tag. This gives us the expected result of
<parent-tag>
<wrapper-tag>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
</wrapper-tag>
</parent-tag>
wrapAll
/**
* Wrap an array of items all at once
*/
function wrapAll(ary, wrapper) {
if (ary && ary.length) {
ary[0].parentNode.insertBefore(wrapper, ary[0]);
for (var i in ary) {
wrapper.appendChild(ary[i]);
}
}
}
How it works
The wrapAll utility takes an array of items and wraps all of them using a methodology expressed in the wrap()
method above. It has a simple check that we have an actual array with values and then runs through them. Then it takes the 1st item who's parent will get our wrapper inserted like before. The difference is we'll go from this:
<parent-tag>
<wrapper-tag></wrapper-tag>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
</parent-tag>
To this..
<parent-tag>
<wrapper-tag>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
</wrapper-tag>
</parent-tag>
unwrap
// unwrap away from an element; super basic but makes it consistent across our apps
function unwrap(el) {
if (el && el.parentNode) {
// move all children out of the element
while (el.firstChild) {
el.parentNode.insertBefore(el.firstChild, el);
}
// remove the empty element
el.remove();
}
}
How it works
If we can wrap then we should be able to unwrap items. For this we take in an element, verify that it has a parent just like before. Then we have to look at ALL the children in this element and act upon them as it could be that we're unwrapping more than one thing. Here's what it looks like before the run it against wrapper-tag
:
<parent-tag>
<wrapper-tag>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
</wrapper-tag>
</parent-tag>
We step into the wrapper tag, target the firstChild
and insert it BEFORE the wrapper. As we go through and append to another item, the value of the firstChild attribute will change to be a reference to the 1st node in the wrapper. That means that in the while
loop we'll have an array that keeps removing items from it and appending just before it like so:
run 1
<parent-tag>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
<wrapper-tag>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
</wrapper-tag>
</parent-tag>
run 2
<parent-tag>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
<wrapper-tag>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
</wrapper-tag>
</parent-tag>
run 3
<parent-tag>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
<tag-we-want-to-wrap></tag-we-want-to-wrap>
<wrapper-tag></wrapper-tag>
</parent-tag>
The last part is to call el.remove()
which is a built in method on all DOM Nodes to self-delete. This effectively deletes the wrapper after we've safely moved everything out of the tag and placed prior to it.
Top comments (1)
Thank you :-)