Internet explorer and removeChild() - javascript

I have been using elem.removeChild() to remove elements from my document, but saving a JavaScript reference to that element, so that I can add them back when appropriate. Works just fine in Firefox and Chrome.
Now I notice that that on IE7, those elements get destroyed in the process, having all their children removed. When I add them back to the same parent element, they are the same type of element and have retained things like their class name, but they have no children elements.
Is this expected behavior? I know I can change my app to do things differently, but it would take a good couple hours of reworking and I'd obviously like to avoid that. I've always assumed that it is ok to remove elements, either by using removeChild() or by setting the parent's innerHTML to an empty string, and as long as I had a reference to the element (i.e. a variable points to the element, not just an element id), it was ok to add and remove elements freely without having the element messed up.
Is this a bug with IE, am I somehow confused and something else is going on, or is this known and expected behavior?

The spec for removeChild doesn't explicitly say that the children of the node being removed should be kept along with that node, although to me it seems logical that they should and obviously that is what the FF and Chrome developers decided too. I don't know what the spec says to do if the parent's innerHTML is set to an empty string, but in my opinion that way is a bit like saying "wipe over whatever was there" so in that case I think it is reasonable for the browser to throw away everything that was in that innerHTML even if there were references in code to some of the removed elements.

Without seeing more of your implementation, I'm not sure you'll get more than blind answers; here's one:
Do you happen to be working with table rows? Check out this answer
. Apparently <tr> has to attach to <tbody> in IE, rather than directly to a <table>.

Related

Adding JS to HTML page, Browser differences

I have simple page that needs very small JS functionality. When i use <script> tag, i get different behaviour on different browsers, depending on where the <script> tag is placed.
On Chrome(65) and Firefox(59) the position of the <script> tag dose not matter and the code is executed before the page is rendered. lets say that i have <h1> and before it I have <script> that uses that <h1> DOM node. It works. Even if i move the <script> to the <head> of the page, it still works.
now if i try the same thing in Edge or IE11 i see what i think is the logical thing, and that is that JavaScript can not see the element if the <script> is before the <h1>.
My question is why we have such different behaviour, isn't this part of a specification? And witch of the bot is the proper way the code should work?
.getElementsByTagName() (along with .getElementsByName() and .getElementsByClassName()) return "live" node lists. These are collections that will always reflect the current state of the DOM, so even if an element gets added or removed after you've declared your collection variable, you will get the most up to date collection. It works because every time you access your variable that references the "live" collection, the DOM is re-scanned. This is great to give you up-to-date results, but not great for performance. So, if your document doesn't dynamically change very much, you are better off not using these methods and instead use .querySelectorAll(), which returns a static node list (one who's content is established at the time of the method call and not updated even if DOM changes occur later) or simply .getElementById() if you are looking for a single element that has an id or .querySelector() if you are looking for only the first element that matches a CSS selector.
Now, here's the important part, no matter what method you use to get any kind of node list (live or static), you will always get a list object back, even if that list is empty.
What you are experiencing across browsers is just the difference in how they report the object itself to you. However, if you were to access some specific aspect of the object or any members of the object, all browsers would give you the same results and if you are querying prior to the element(s) being parsed, you will have a node list with 0 items in it. This is why it's a best-practice to place your scripts that need access to DOM elements just before the closing body tag (</body>), because by that time, all the HTML has been parsed and you will definitely be able to find all elements.
As Felix Kling found, i was using document.getElementsByTagName() with returns live list. Combined that with the fact that I was verifying the result with console.log() that in Chrome and Firefox gets the value of the list when I clicked the expand button, therefore I see my element. In IE and Edge, what is printed in the console is directly displayed with the current value of the live list, that had no elements at that time.
10x a lot for the quick response to everybody :)

Is putting an empty string in .outerHTML equivalent to remove()?

So if I have a <span class="iii"></span> container... and I use you know:
document.querySelector('.iii').outerHTML=''; it removes the span and essentially removes that span element from the DOM and everything inside of it correct? Is it really, technically deleting/removing it from the DOM? Does it perform what remove() does?
I ask this, because .remove() is a new experimental method that is not cross browser correct? I'm trying to find a cross browser way to 'remove an element', and outerHTML = ''; does that for me, but I am asking this question because it doesn't seem right. outerHTML's function isn't for deleting, (or can it be) or is it?
Edit: added .iii my bad.
There is no difference, both will remove the element from the DOM removing all event handlers and other related properties from memory when the garbage collector decides to. As for performance I wrote a quick test, http://jsperf.com/outerhtmlblank-vs-remove and it turns out that outerHTML = '' is 14% faster on Google Chrome so I would say that is better to use. Feel free to test on other browsers to confirm the results.
When you call outerHTML = '' it sets the HTML around it to nothing, then when the browser updates it's representation of the DOM it realizes that the element is now gone and removes it from the DOM whereas remove() simply removes it from the DOM.
There doesn't seem to be any significant difference between them when it comes to removing elements from the DOM. For your case they both remove the element, and that's the end of the story.
Here are the most obvious differences that come to mind (feel free to add any other ones):
outerHTML
It is a getter
It is a setter (for the setter version it can be used to either "remove" or "replace" an element)
When you're either removing or replacing an element, you don't need to know its parent like you would need to with el.parentNode.removeChild(el)
It works only with strings, which are then parsed into DOM objects
It is a property and not a method
It is supported by most Browsers
remove
It is a method
It can remove Element and Text nodes where outerHTML isn't available on text nodes
It can only work with DOM objects and not strings
You don't need to know the element's parent, instead you just remove it
It's not supported by most Browsers as it's new

Remove an element ( and its children ) from the DOM

Via the MDN reference I want to simply do:
parent_element.removeChild(child_element);
However, in this particular case child_element has its own child elements.
Can I assume that this will not cause any problems and that they too will be removed.
The examples given in the reference did not make complete sense.
Yes when you remove an element from the DOM, all of its children are removed with it. If you are working with a modern browser, this is pretty safe. Older browsers tended to get memory leaks if you did not first remove all your event handlers before removing the elements.
Yes, all elements that are childs of a removed element are removed. You don't need to implement a deep removal yourself.
yes you can assume that the child's children will be removed
If the children didnt get removed, where or how could they exist in the DOM, unless someone put them somewhere else.

In JavaScript what is the right way to kill a DOM element?

I know that I can set it's style to "display: none"
However, that just hides it.
I really want to kill a DOM element and all of it's children.
The context is that I'm building a desktop-like GUI system (for learning purposes) inside of a DOM, and when a "window" is closed, I want that DIV and all it's children to be removed.
Thus, in JavaScript, how to I tell the GC "hey, get rid of this DOM element, it's no longer needed"?
Thanks!
To remove all elements, I suppose you could set element.innerHTML to an empty string (although I've never tried it myself). Otherwise, you could use element.removeChild(child), as described here.
jQuery also supports $([selector]).remove([selector]), which is more flexible in specifying which elements you want to remove at once. There's more information about jQuery remove here.
What about removeChild ?
See http://dustindiaz.com/add-and-remove-html-elements-dynamically-with-javascript/ for more information

Javascript removeChild() and appendChild() VS display=none and display=block|inline

I'm developing a web application that shows some controls and descriptions dynamically (I don't want to use jQuery or other libraries).
At this moment i make appear and disappear controls using:
element.setAttribute("style", "display : inline");
and
element.setAttribute("style", "display : none");
but i'm thinking about using:
element.appendChild(childRef);
and
element.removeChild(childRef);
So, which one is the best solution in terms of system speed and elegance of the code?
Or is there a better way to go about this?
element.appendChild(childRef); and element.removeChild(childRef); both make the browser to manipulate the DOM tree while changing CSS just changes one of the attributes.
So, changing CSS is faster.
Dev Opera says
When an element has its display style set to none, it will not need to repaint, even if its contents are changed, since it is not being displayed. This can be used as an advantage. If several changes need to be made to an element or its contents, and it is not possible to combine these changes into a single repaint, the element can be set to display:none, the changes can be made, then the element can be set back to its normal display.
This will trigger two extra reflows, once when the element is hidden, and once when it is made to appear again, but the overall effect can be much faster
Another relevant article explains about reflow and repaint
Definitely go on using display properties.
They are much faster than removing/appending children, but most important they work very well in every browsers.
I know appendChild/removeChild are supposed to be well supported in IE, but sometimes on my IE7 a still get things moving around after a new element is appended (this is only my personal experience).
Regarding the way you change the display properties I would simply do a more easy and cross-browser (setAttribute is not well supported by IE6/7 an also IE8 when in IE7 mode):
element.style.display = 'none'; //for hiding an element
element.style.display = ''; //for showing that element again using its default way of displaying
Showing an element by using display = 'inline' is wrong because the element might have by default a display block way of showing like DIV tags and you are changing its way of showing to inline wich is not correct and might lead to elements in your page moving out from the places you expect them to be.
I doubt there's much in it one way or the other, and even if there is, I bet it varies by implementation (IE vs. Chrome vs. Firefox vs. ...). Both will cause reflow events in the tree.
Showing and hiding is simple and straightforward. Adding and removing can have its uses, but for the most part is probably overkill. For one thing, you have to keep a reference to it so you can add it back later, and you have to remember where you need to add it back.
But (and this is a bit off-topic) your mechanism for showing and hiding has some issues:
With your example code, things can only be inline, not inline-block or block, which would be somewhat...limiting.
Your code also completely replaces the style information on the element (and may not work on IE; see David's comment on your question), so all other styles directly applied to the element will get blown away; consider using the style property of the element instead: childRef.style.display = 'none"; and childRef.style.display = "inline"; (or block, or...). That way, you don't bludgeon any other styles on the element.
Completely removing a child from the tree (while keeping a reference to it so you can put it back later) definitely has its uses, though. For instance, when it's not in the tree, it won't be found when you're walking the tree with selectors for doing this, that, and the other; which may be helpful.
A small aside: if you happen to be dealing with user editable elements in IE (i.e. inside a document with designMode "on" or inside an element with contenteditable true), setting the CSS display property to none won't have any effect, and you'll need to remove the elements from the DOM to hide them.
The first approach is better i think which just hides and displayes but does not remove from the DOM and add again.
I would think that performance is better just updating the style.
The answer will depend on what you are using the elements for. If it is very dynamic whether they should be shown or not, it might be a solution to add/remove from DOM, but if there are a static set of elements, it might be easier to set the style. Setting the style, you also have more control of the position in the document. Adding/removing from DOM, you need to be sure it is added at the right place.
Note:
Instead of element.setAttribute("style", "display:none"); you can use element.style.display= "none"; If you use the first approach, you will remove any other style settings on the element.
I think editing the style of an element will be faster, but which is better hide the element or remove it from dom, this depends on your needs, if you need to just hide the element or remove it.
May be you don't need the user see the element but you need to do some js logic on it, so hide here will be the best.

Categories