Can I keep a reference to a document fragment? - javascript

I'm playing around with a document fragment. I find it hard to understand how it behave when I append it to the DOM.
I create a doc fragment that I assign to a variable, when I insert some stuff into it, and append the doc fragment into a element. But if I clear the element my variable which should reference to the doc fragment contain an empty document fragment.
I trying to make a cache for a third party lib that creates document fragments. So I would like to get this working. Should I create a cloneNode before I append the fragment to the DOM, is that correct?
I have created a JS fiddle:
http://jsfiddle.net/4CTXG/1/
var test = document.createDocumentFragment();
//var test = document.createElement("div"); // This one work
$(test).append($("<div>").html('Hello world!'));
$("#result").append(test);
setTimeout(function(){
$("#result").children().remove();
$("#result").append(test);
console.log('Now test should have been appended');
$(result).css({"background": "#FF0000"});
},5000)

When you append an Element (e.g. the <div>) into the DOM, the Element gets added as a child of its new parent. The div's children are not changed. When you remove the element from its parent, the Element is just detached from the DOM. It you still have a reference to the Element it will still contain its children, available to reattach later.
When you append an DocumentFragment into the DOM, the children of the DocumentFragment are removed from the DocumentFragment and moved to be children of its DOM element parent. The DocumentFragment is now empty.
So instead of appending the DocumentFragment, you should append a deep clone of the fragment.
See http://dom.spec.whatwg.org/#concept-node-insert for the gory details.

Javascript objects are copied by reference rather than value. So when you assign the fragment to a variable and then insert the fragment into the DOM, both the variable and the DOM are referencing the same object. Any change you make to one will also occur in the other.
If you really want the variable to reference an object that is distinct from the DOM, then cloning is the right approach.

Related

What's the efficient way to insert elements from array to existing Html element?

I have heard few approaches:
I could simply iterate through 20k elements and do appendChild.
I could insert All items into newly created div in js and then just put that div into parent dom.
Is there any other approach? Copy html wholesale?
However, I am confused on how to do 2. What is the best way to move all child element from div A to div B without iterating over all of them.
You can also use document fragment which appends all at one moment
var fragment = document.createDocumentFragment();
fragment.appendChild(...)
fragment.appendChild(...)
...
element.appendChild(fragment)
According to this source the fastest is to simply iterate through the elements and append them.
Far better than creating a random div is to create a document fragment and append to that fragment. Then, said fragment can be added to the dom
var fragment = document.createDocumentFragment()
arr.forEach(el => fragment.appendChild(el))
element.appendChild(fragment)
I made a jsPerf that contains an experiment about which of these two are faster. It appears that using document fragment is the same as raw append with my limited test (one browser, one OS)
Why not just using cloneNode() in deep mode:
// Copy the element and its child nodes
var cln = itm.cloneNode(true);
// Append the cloned element to the new div with id="new_div"
document.getElementById("new_div").innerHTML(cln);
Hope this helps.

How to detect an jquery element is in DOM?

I have a jquery element. and I remove it from DOM by using remove(), but jQuery still keep a reference of it.
and later I still can use it and insert it into DOM.
How to detect that this "var p" is in DOM or off DOM ?
var p=$('p');
p.remove();
console.log(p);
p.insertAfter($('body'));
I think p.parent() is more easy way to go. if it in DOM it will get another DOM node
use javascript length to check if dom element exists or not
if($("p").length>0)
{
// p exists
}
var p=$('p');
p.remove();
So when you did p.remove(), it is removed from the dom but it still exists in memory as a stand alone dom node object with all its contents intact.
You can perform any operation as in normal dom element like append anywhere, change contents or change attributes.
The only difference is that it is not part of the document unless you append it in the html.
jQuery has contains method to check if the element is part of the document
jQuery.contains(document, $foo[0]));
p.parent() in case of removed p will return a 0 length jquery object because p is independent node and has no parent.

puzzled about document.documentElement

I got puzzled about it .
1 Is document equal to document.documentElement? I think they are both root node.
2 Why I can use document.documentElement.getElementsByTagName() but I can not use
document.documentElement.getElementById()?
There is a difference between the document object and the document element.
When an HTML document is loaded into a web browser, it becomes a document object.
The document object is the root node of the HTML document and the common ancestor of all other nodes, such as element nodes (including the document element), text nodes and attribute nodes.
One of the differences is that an element has getElementsByTagName() but not getElementById(), which is part of the document itself.
To successfully use an element to get another one based on ID, you need to go through its document:
var elem2 = elem1.ownerDocument.getElementById(whatever)

How to insert a HTML fragment and hold a reference to the outer element?

I've always wondered how this jQuery feature works: $('<span>Hello world</span>')[0]
That is supposed to return a reference to the newly created span element. How can I achieve the same result using the native DOM methods? insertAdjacentHTML? innerHTML? documentFragment?
I need to insert a HTML fragment and hold a reference to the outer element without the need of using createElement/appendChild.
Thanks.
It's possible to create an element, set its innerHTML, and return the first child. The container element is never added to the DOM:
var el = document.createElement('div');
el.innerHTML = '<span>Hello world</span>';
console.log(el.firstChild);
If that's wrapped in a function, I believe the original container will be eligible for garbage collection as soon as the child is appended somewhere else.
jQuery seems to be doing something more sophisticated, checking if the string contains a single tag or not, and creating a fragment for more complicated strings. See the parseHTML method on jQuery's source code.

Javascript append fragment to an existing HTML element

I have created a DOM fragment where I am adding several childNodes in a loop:
fragment.appendChild( clone )
I want to take this fragment and use it to replace an existing HTML element that already contain those nodes.
I can use
myContainer.appendChild(fragment)
However this is done also in a loop and the fragment is appended too many times.
How can I get the fragment, append it to myContainer and delete also myContainer's old childs.
Thank you.
You probably want:
while (myContainer.childNodes.length > 0) {
myContainer.removeChild(myContainer.childNodes[0]);
}
myContainer.appendChild(fragment);
Can you not append the Fragment after the loop has finished?
As for removing the current child nodes, you could cycle through them all and use the removeChild function, or you could just set the innerHTML of the element to an empty string. If you reset the innerHTML before you append the fragment it should be fine.
myContainer.innerHTML = "";
myContainer.appendChild(fragment);
If I understand you correctly, you are creating a new node with some children, and you want this new node to replace an existing node in your page.
You can either:
Remove all children of the existing node, and add the new children to the existing node
Add all the children to another node (I think that is what you are doing: adding to the fragment), then remove the existing node, and add the node to that place.
See removeChild and appendChild

Categories