Home > OS >  Get elements in Javascript "consumed" by adding / appending them in the dom?
Get elements in Javascript "consumed" by adding / appending them in the dom?

Time:11-28

I have 4 dropdown menus: fs2_beginn, fs3_beginn, fs2_ende and fs3_ende, which all should filled with options with both texts and values 5, 6, .., 10.
I've a function (called during onload) with a nested loop which does the task:

for(let j=2;j<=3;j  )
{
      let fsDropdown1 = document.getElementById('fs' j '_beginn');
      let fsDropdown2 = document.getElementById('fs' j '_ende');
      for( let i = 5; i <=10; i  ){ 
          fsDropdown1.add(new Option(i,i));
          fsDropdown2.add(new Option(i,i));
      }
}   

If one defines let x=new Option(i,i); and replaces the add's by add(x) only the second add will do. Question 1: Why?
If one replaces the body of the inner loop by

let fsOption = document.createElement('option');
fsOption.text  = i;
fsOption.value = i;
fsDropdown1.add(fsOption);
fsOption = document.createElement('option');// Line 1
fsOption.text  = i; // Line 2
fsOption.value = i; // Line 3
fsDropdown2.add(fsOption);

it will work too, but I wonder, why are the lines 1-3 are necessary? (otherwise only the first add will do).
So, my question 2 is: Get objects in a way "consumed" during adding?
(The same behavior is seen, if one use appendChild; I also tried several combinations of let, var and const, which had no effect.)

CodePudding user response:

Javascript objects (those native to the language) can indeed be added to multiple containers, just like in Java, consider for example:

let obj = {foo: 1}

let container1 = []
let container2 = []

container1.push(obj)
container2.push(obj)

console.log(container1, container2)

// prove it's the same object

obj.foo  
console.log(container1, container2)

That is, the container->containee relationships form an arbitrary directed graph. In fact, it can even be cyclic, so that an object can directly or indirectly contain itself.

However, the DOM elements (those created with createElement) have dual nature.

Firstly, they are normal Javascript objects, and as such, can be added to arbitrary many Javascript containers.

Secondly, they are part of the DOM. Unlike Javascript's arbitrary graph, DOM is a tree, that is, an element can belong to only one DOM container at a time. Once you attach an element to a new DOM container, it is automatically removed from the old one.

Illustration:

let obj = document.createElement('input')

let array1 = []
let array2 = []

// obj is a Javascript object 
// and can live in multiple containers

array1.push(obj)
// now, it's attached to array1
array2.push(obj)
// now, it's attached to array2 AND still to array1

//-------------------------------------------------------

// however, as a DOM node,
// obj can have only one DOM parent

document.querySelector('#A').appendChild(obj)
// now, it's attached to A

document.querySelector('#B').appendChild(obj)
// now, it's attached to B, BUT not to A anymore
<div id="A">A: </div>
<div id="B">B: </div>

The bottom line: you cannot add the same DOM element to multiple DOM parents. You have to create identical objects, e.g. with a factory function (recommended) or use the cloneNode API.

  • Related