Search code examples
javascriptarrayscopyelementnodes

How to copy the elements of the copied element into an array without looping through it?


Can you please tell me how to copy elements to an array without going through them again through getElementsByTagName("*"), and so that they refer to the copied element?

HTML:

<div id="id1"><p id="p1">1</p><p id="p2">2</p></div>

JS:

const el = document.getElementById("id1");
const arr = [];
if(el)
for (const element of el.getElementsByTagName("*")) {
  if(element.textContent === "1") arr.push(element)
}
const cloneEl = el?.cloneNode(true);
function arrCloneWithRelationToCloneEl(arr , cloneEl){
...
return arrClone;
}

Result:

arrClone = [p#p1]

from cloneEl.

Can this be done at all without iterating over the nodes of the cloned element, but somehow by id in childNodes or by creating a virtual DOM to do it? Maybe there is some special function for copying, only to not have to loop every time an object is cloned.

I will be very grateful for the answer!

I tried to do it through creating path in childNodes array. Something like this array [0,0] in results.


Solution

  • First, using document.getElementById doesn't clone the node. It gets the element as an object of the DOM API.

    For your use case by getting a child element with a specific .textContent, there isn't any function you can use to get the element. However, you can shorten your code by a lot by converting el.getElementsByTagName("*") into an array using spread syntax, then using .filter() to only get sub-elements with the specified .textContent. To handle el being null, you can use a quick ternary expression to return an empty array if the element doesn't exist:

    const el = document.getElementById('id1');
    const arr = el ? [...el.getElementsByTagName("*")].filter(x => x.textContent == '1') : [];
    
    console.log(arr);
    <div id="id1">
      <p id="p1">1</p>
      <p id="p2">2</p>
    </div>

    However, if you're instead looking for an element with a certain attribute, class, or anything else that can be searched for with a CSS selector, then you can use el.querySelectorAll and once again use spread syntax to convert to an array:

    const el = document.getElementById('id1');
    const arr = el ? [...el.querySelectorAll('[x-attribute="1"]')] : [];
    
    console.log(arr);
    <div id="id1">
      <p id="p1" x-attribute="1">First element</p>
      <p id="p2" x-attribute="2">Second element</p>
    </div>