最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Replace element with outerHTML and immediately access the newly created element - Stack Overflow

programmeradmin3浏览0评论

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.

Share Improve this question edited Jul 23, 2015 at 4:23 sampathsris asked Jul 21, 2015 at 22:47 sampathsrissampathsris 22.3k12 gold badges72 silver badges101 bronze badges 4
  • 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 applying code to e.innerHTML, then you set e.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
Add a ment  | 

3 Answers 3

Reset to default 10

Finally 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

发布评论

评论列表(0)

  1. 暂无评论