Je remplace un élément DOM en remplaçant son contenu par outerHTML. L'astuce fonctionne, mais j'ai besoin d'accéder immédiatement à l'élément DOM nouvellement créé.

Malheureusement, la création de l'élément <x> et la génération du contenu de var code ne sont pas sous mon contrôle.

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>

Le comportement est expliqué dans les notes de MDN sur outerHTML:

De plus, bien que l'élément soit remplacé dans le document, la variable dont la propriété externalHTML a été définie contiendra toujours une référence à l'élément d'origine.

Ma question est donc la suivante: comment puis-je accéder aux éléments nouvellement ajoutés immédiatement après avoir remplacé l'ancien élément?

PS: je suis prêt à abandonner outerHTML s'il y a un autre moyen que je peux utiliser pour remplacer un élément et accéder ensuite à l'élément nouvellement créé.

4
sampathsris 22 juil. 2015 à 01:47

3 réponses

Meilleure réponse

Enfin, je me suis contenté d'insérer le nouvel élément avant , en utilisant insertAdjacentHTML, obtenant le nouvel élément en appelant previousSibling, puis en supprimant l'élément inutile avec 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>
3
sampathsris 4 avril 2017 à 07:28

J'ai réussi à bien le faire en utilisant le javascript suivant:

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

Ce sont mes changements:

/**
 * 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>

Voici un Codepen avec le code afin que vous puissiez modifier le jeu avec lui: http://codepen.io/nicholasabrams / pen / VLGMgj

1
sampathsris 23 juil. 2015 à 04:31

Pourquoi ne pas donner un identifiant au div généré? Vous pouvez alors obtenirElementById sur le nouvel élément.

Par exemple.

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);
1
Benjamin 21 juil. 2015 à 23:15