2

I stumbled upon something peculiar (at least to me). Here is the case:

I select an element, child1, from the DOM and save it to a variable. I continue on by adding a new element to child1's parent, parent1. Now if I try to modify some value on child1 it does not register the change. It seems as though the reference has disappeared and it is only referring to an earlier copy.

EXAMPLE
child1 = inputField
parent1 = container

function start() {
    var inputField = document.querySelector('#inputField');
    // Works if addSomething() is commented out.
    addSomething();
    console.log(inputField);
    doSomething(inputField);
}

function addSomething() {
    var container = document.querySelector('#container');
    container.innerHTML += '<div class="something"></div>'
}

function doSomething(el) {
    el.value = 'Some random input';
}

start();

EXAMPLE FIDDLE

http://jsfiddle.net/mdTkZ/

Excuse me if this is something incredibly basic or something that has been asked before. I tried googling, but did not find anything with the search words I used. A

Uirri
  • 263
  • 1
  • 10
  • try `console.log(inputField.value)` after `doSomething`. It is getting modified. What do you want exactly ? – schnill Jun 24 '14 at 10:13
  • 1
    I don't want to achieve anything in particular, actually. I just want to get a better understanding of how stuff works :p. – Uirri Jun 24 '14 at 10:30

6 Answers6

5

container.innerHTML += ... doesn't do what you think it does. It re-creates all the HTML to the element, and the original content is gone.

To fix this you need to create a new div and append it to container.

var div = document.createElement('div');
div.className = 'something';
container.appendChild(div);

A live demo at jsFiddle.

Teemu
  • 22,918
  • 7
  • 53
  • 106
  • Thanks for the answer Teemu! Considering the the original content is gone when doing the 'container.innerHTML += ...' why does the inputField variable seem to contain the correct element? How come it is not turned into undefined or null? Is a copy generated and it references the copy? – Uirri Jun 24 '14 at 10:28
  • 1
    No, it's not a copy. You've still a reference (`inputField` and later `el` variables) to the original `input`. The element is removed from the DOM, but it remains available to the script (the removed element is in a same kind of a state as the `div` in my fix code just before `appendChild()`, i.e. it is created, but it has not parent element, hence you can't see it.) untill `inputField` and `el` are deleted. You can even [append the original element back](http://jsfiddle.net/pj8W9/) to the document, as long as a reference to it is alive. – Teemu Jun 24 '14 at 10:48
  • For this reason, I consider `element.insertAdjacentHTML("beforeend", "
    ")` to be a much better way of appending HTML to an element.
    – Tikolu Jun 08 '23 at 23:53
  • @Tikolu Which method to use depends on the actual use-case. It's easy to avoid memory leaks when using block scoped variables (or a function in this old ES3 code). – Teemu Jun 09 '23 at 04:14
1

When replacing innerHTML on object you removing inputField from the DOM so the object changes does not register in the browser

container.innerHTML += '<div class="something"></div>'

You actually do

container.innerHTML = container.innerHTML + '<div class="something"></div>';
Moti Korets
  • 3,738
  • 2
  • 26
  • 35
  • For this reason, I consider `element.insertAdjacentHTML("beforeend", "
    ")` to be a much better way of appending HTML to an element.
    – Tikolu Jun 08 '23 at 23:53
1

When you do container.innerHTML += '<div class="something"></div>', it replaces the content with some other text.

inputField which you had before changing innerHTML, was holding a reference to DOM object. But now, that is destroyed and is replaced by just a string. You would need to access/select that input from DOM again ( by document.querySelector('#inputField'); ) to use it.

Jashwant
  • 28,410
  • 16
  • 70
  • 105
0

You are replacing the entire DOM subtree by setting innertHTML. inputField is now detached from its parent. You can check it by logging inputField.parentNode === null.

You can use insertAdjacentHTML instead.

function addSomething() {
    var container = document.querySelector('#container');
    container.insertAdjacentHTML('beforeend', '<div class="something"></div>');
}

http://jsfiddle.net/tarabyte/mdTkZ/1/

Yury Tarabanko
  • 44,270
  • 9
  • 84
  • 98
0

From this: Is it possible to append to innerHTML without destroying descendants' event listeners?

"Unfortunately, assignment to innerHTML causes the destruction of all child elements, even if you're trying to append"

You could use: https://developer.mozilla.org/en-US/docs/Web/API/element.insertAdjacentHTML

Community
  • 1
  • 1
benhowdle89
  • 36,900
  • 69
  • 202
  • 331
0
Try this
    var inputField;
    function start() 
    {
        inputField = document.getElementById('inputField');
        // Works if addSomething() is commented out.
        addSomething();
        console.log(inputField);
        doSomething(inputField);
    }

    function addSomething() 
    {
        var t=document.getElementById('container').innerHTML;
        document.getElementById('container').innerHTML = t+'<div class="something"></div>'
    }

    function doSomething(el) 
    {
        el.value = 'Some random input';
    }

    start()
Unknownman
  • 473
  • 3
  • 9