Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I update the reference to an HTML element after I used appendChild with native javascript

I'm using native javascript to append an element to my DOM, which disappears after X seconds.

To append the element I create a document fragment with a function createHTML I then append this element to my container element.

var elementHTML = '<div>Test element appended</div>';
    elementHTML = createHTML(elementHTML);      
document.getElementById('append-container').appendChild(elementHTML);

I then set a timeout that removes the element from the DOM after x seconds

setTimeout(function() {
    elementHTML.parentNode.removeChild(elementHTML);
}, 2000, elementHTML); 

Now this won't work because when you use appendChild, the elements get moved and the reference to the element is lost. I'm looking for a way to update the reference for elementHTML to the element I just appended to the DOM.

Basically I'm looking for the jQuery reference funcionality without using jQuery.

I could use a randomly generated ID to target the element or add a class and loop trough all the elements with that class and target the last one, but these methods feel ugly.

I'm wondering if there is some sort of callback when you append something to the DOM to target what you just appended or if my logic in going about this is just plain wrong.

FIDDLE

like image 873
timo Avatar asked Mar 07 '19 07:03

timo


1 Answers

The issue is that a DocumentFragment will move the contents of the fragment into the new place in the DOM, but the fragment itself will remain a fragment, not directly attached to anything:

https://developer.mozilla.org/en-US/docs/Web/API/Node/appendChild

If the given child is a DocumentFragment, the entire contents of the DocumentFragment are moved into the child list of the specified parent node.

After all, otherwise, if the HTML string is

<div>Test element appended</div><div>Test element 2 appended</div>

what could the appended documentFragment refer to? It's couldn't be just one or the other <div>, nor could it be the parent element (which was already in the DOM, and was not created with the fragment).

So, once a documentFragment is appended, it cannot be removed all in one go.

If the fragment is guaranteed to contain only one element, like in your example, then select that one element and append it instead (and then you can properly reference its parentNode).

// though using a documentFragment in the first place is a bit odd
// if you're not going to append it

var createHTML = function(htmlStr) {
  var frag = document.createDocumentFragment(),
    temp = document.createElement('div');
  temp.innerHTML = htmlStr;
  while (temp.firstChild) {
    frag.appendChild(temp.firstChild);
  }
  return frag;
}

var appendItems = function() {
  const elementHTML = '<div>Test element appended</div>';
  const fragment = createHTML(elementHTML);
  const fragmentElm = fragment.children[0];
  document.getElementById('append-container').appendChild(fragmentElm);
  setTimeout(function() {
    fragmentElm.parentNode.removeChild(fragmentElm);
  }, 2000, elementHTML);
}

document.getElementById('test-append').addEventListener('click', appendItems);
<div id="append-container">

</div>

<button id="test-append">
  Test
</button>

Another option is to iterate through all appended nodes and .remove() them:

var createHTML = function(htmlStr) {
  var frag = document.createDocumentFragment(),
    temp = document.createElement('div');
  temp.innerHTML = htmlStr;
  while (temp.firstChild) {
    frag.appendChild(temp.firstChild);
  }
  return frag;
}

var appendItems = function() {
  const elementHTML = '<div>Test element appended</div><div>Test element 2 appended</div>';
  const fragment = createHTML(elementHTML);
  const fragmentElms = [...fragment.children];
  const container = document.getElementById('append-container');
  fragmentElms.forEach((elm) => {
    container.appendChild(elm);
  });
  setTimeout(function() {
    fragmentElms.forEach((elm) => {
      elm.remove();
    });
  }, 2000, elementHTML);
}

document.getElementById('test-append').addEventListener('click', appendItems);
<div id="append-container">

</div>

<button id="test-append">
  Test
</button>
like image 56
CertainPerformance Avatar answered Oct 06 '22 16:10

CertainPerformance