I am replacing a DOM element by replacing its content with outerHTML
. The trick works, but I need to immediately access the DOM element that was newly created.
Unfortunately the creation of element <x>
and generation of the contents of var code
is not under my control.
var code, e;
(function () {
/**
* Things done inside this IIFE is not under my control
*/
code =
'<div style="border: 1px solid black;">' +
' <span>I </span>' +
' <span>want </span>' +
' <span>to </span>' +
' <span>access </span>' +
' <span>all </span>' +
' <span>these </span>' +
' <span>spans.</span>' +
'</div>';
e = document.getElementById('replace_this');
}());
e.outerHTML = code;
// by this point, element e is replaced with newly added HTML. Let's do
// an alert to make sure
alert('Check the document. New HTML is rendered.');
var spans = e.getElementsByTagName('span'); // oops! empty collection
alert(spans.length); // alerts 0
alert(e.outerHTML); // alerts '<x></x>'
<div id="container" style="padding: 20px; border: 1px dashed grey;">
<div>Don't replace this.</div>
<x id="replace_this"></x>
<div>Don't replace this either.</div>
</div>
I am replacing a DOM element by replacing its content with outerHTML
. The trick works, but I need to immediately access the DOM element that was newly created.
Unfortunately the creation of element <x>
and generation of the contents of var code
is not under my control.
var code, e;
(function () {
/**
* Things done inside this IIFE is not under my control
*/
code =
'<div style="border: 1px solid black;">' +
' <span>I </span>' +
' <span>want </span>' +
' <span>to </span>' +
' <span>access </span>' +
' <span>all </span>' +
' <span>these </span>' +
' <span>spans.</span>' +
'</div>';
e = document.getElementById('replace_this');
}());
e.outerHTML = code;
// by this point, element e is replaced with newly added HTML. Let's do
// an alert to make sure
alert('Check the document. New HTML is rendered.');
var spans = e.getElementsByTagName('span'); // oops! empty collection
alert(spans.length); // alerts 0
alert(e.outerHTML); // alerts '<x></x>'
<div id="container" style="padding: 20px; border: 1px dashed grey;">
<div>Don't replace this.</div>
<x id="replace_this"></x>
<div>Don't replace this either.</div>
</div>
The behavior is explained in MDN's notes on outerHTML
:
Also, while the element will be replaced in the document, the variable whose outerHTML property was set will still hold a reference to the original element
So my question is, how can I access the newly added elements immediately after I replaced the old element?
PS: I am ready to abandon outerHTML
if there's another way that I can use to replace an element and then access the newly created element.
-
1
You won't be able to, because you've effectively deleted the parent element
e
. The object still remains with an old copy of the HTML. You can trick it by applyingcode
toe.innerHTML
, then you sete.outerHTML = e.innerHTML
, but again this is operating off a now non-existent list of nodes. I would not suggest this method as it may function differently in different browsers. – user4639281 Commented Jul 21, 2015 at 22:56 - I have no trouble accessing it using your code plus: var target = document.getElementById('container'); alert(elementChildren(target)[0].children.length); for (var i = 0; i < elementChildren(target)[0].children.length; i++) { elementChildren(target)[0].children[i].style.border = '1px red solid'; alert(elementChildren(target)[0].children[i].innerHTML); } – AlphaG33k Commented Jul 21, 2015 at 23:28
- Is this not what you are looking for? – AlphaG33k Commented Jul 21, 2015 at 23:35
-
@AlphaG33k: That won't generalize. It will work until element
#container
has only one child. This is not the case with me. Thanks for the help though. – sampathsris Commented Jul 22, 2015 at 4:58
3 Answers
Reset to default 10Finally I settled for inserting the new element before, using insertAdjacentHTML
, getting the new element by calling previousSibling
, and then removing the unnecessary element with parentElement
.
removeChild
var code, e;
(function () {
/**
* Things done inside this IIFE is not under my control
*/
code =
'<div style="border: 1px solid black;">' +
' <span>I </span>' +
' <span>want </span>' +
' <span>to </span>' +
' <span>access </span>' +
' <span>all </span>' +
' <span>these </span>' +
' <span>spans.</span>' +
'</div>';
e = document.getElementById('replace_this');
}());
// insert the new element just before <x>
e.insertAdjacentHTML('beforeBegin', code);
// now <x>'s previousSibling should be the newly added element
var new_elem = e.previousSibling;
// get rid of <x>
e.parentElement.removeChild(e);
// by this point, element e is replaced with newly added HTML. Let's do
// an alert to make sure
alert('Check the document. New HTML is rendered.');
var spans = new_elem.getElementsByTagName('span');
alert(spans.length); // alerts 7
alert(new_elem.outerHTML); // alerts contents of new element
<div id="container" style="padding: 20px; border: 1px dashed grey;">
<div>Don't replace this.</div>
<x id="replace_this"></x>
<div>Don't replace this either.</div>
</div>
Why not give the generated div an id? You could then getElementById on the new element.
eg.
var code =
'<div id="newElement" style="border: 1px solid black;">' +
' <span>I </span>' +
' <span>want </span>' +
' <span>to </span>' +
' <span>access </span>' +
' <span>all </span>' +
' <span>these </span>' +
' <span>spans.</span>' +
'</div>';
var e = document.createElement('x');
document.getElementById('container').appendChild(e);
e.outerHTML = code;
// by this point, element e is replaced with newly added HTML. Let's do
// an alert to make sure
alert('Check the document. New HTML is rendered.');
e = getElementById('newElement'); // reassign e to the new div
var spans = e.getElementsByTagName('span');
alert(spans.length);
alert(e.outerHTML);
I managed to get it fine using the following javascript:
var code =
'<div style="border: 1px solid black;">' +
' <span>I </span>' +
' <span>want </span>' +
' <span>to </span>' +
' <span>access </span>' +
' <span>all </span>' +
' <span>these </span>' +
' <span>spans.</span>' +
'</div>';
var e = document.createElement('x');
document.getElementById('container').appendChild(e);
e.outerHTML = code;
var spans = e.getElementsByTagName('span'); // oops! empty collection
These are my changes:
/**
* Return direct children elements.
*
* @param {HTMLElement}
* @return {Array}
*/
function elementChildren(element) {
var childNodes = element.childNodes,
children = [],
i = childNodes.length;
while (i--) {
if (childNodes[i].nodeType == 1) {
children.unshift(childNodes[i]);
}
}
return children;
}
var target = document.getElementById('container');
alert(elementChildren(target)[0].children.length);
for (var i = 0; i < elementChildren(target)[0].children.length; i++) {
elementChildren(target)[0].children[i].style.border = '1px red solid';
alert(elementChildren(target)[0].children[i].innerHTML);
}
<div id="container" style="padding: 20px; border: 1px dashed grey;"></div>
Here is a Codepen with the code so you can edit play around with it: http://codepen.io/nicholasabrams/pen/VLGMgj