Revealing the magic: How to properly convert HTML string to a DOM element
This seems like a trivial task. However, it is not. There are few popular solutions, but they have a big problem and if you use them a lot you will spot the issue.
Let's say that we have the following HTML markup:
If you google the problem you will find that the most popular solution involves the usage of .innerHTML property of a newly created element.
The result of the above script is actually correct. You will get section element with link inside it. Everything seems ok and it looks like you did the trick. Now let's try with something else:
The result is only
Hm . the <tr> and <td> tags are missing. This seems wrong isn't it. Actually that's kinda correct behaviour of the browser. I searched for similar problems and landed on this article by Eric Vasilik. Here is what he said back at 2006:
"When one sets the innerHTML property of an element, the string containing the HTML is run through the parser."
"Now, parsing something like "<tr><td>Foo" where there is no TABLE tag preceding the TR causes the parser to ignore the TR tag altogether."
So, I realize that the string which is passed to .innerHTML shouldn't be just a mix of tags. It should be a valid DOM representation. If I want to use the function above I should pass <table> tag as well. And I did, I tried with the following code:
and the result was:
Which proves the words from Eric Vasilik. My method should somehow examine the passed HTMl and automatically adds the necessary tags. Along with that it should return not the first child node, but the correct nested element. Looks like a lot of work.
Ok, but . wait a minute. jQuery doesn't have this problem. You may pass <tr><td>Text Here</td></tr> and still get the desired result. I started digging into the jQuery's code and found this:
This looks like the magic which solves the problem. I cheated a bit and got the code above. I managed to extract that functionality into a single method:
The map of jQuery nicely shows me what exactly I should wrap my string in. There are few lines of code which find the root tag and its type. At the beginning I wondered what are this numbers in the wrapMap object for. Later I found this:
That was the code that returns the needed DOM element from the build tree. And the numbers were the level of nesting. Pretty simple, but I think, one of the most used features of jQuery.
There is a special case when you want to create a new body tag. The function above doesn't work because the div element could not have a body inside. Here is the fixed version.
Friends
Markup as function