Javascript: Failed to execute 'removeChild' on 'Node': parameter 1 is not of type 'Node'

Steve picture Steve · Jul 7, 2015 · Viewed 8.2k times · Source

i am trying to recreate a some practices from one of the courses. Its about to remove a li-item from an UL and append it to another UL.

When i write my code in the following way all works finde

var removeMeandAppendMe = function() {
    var parentLi = this.parentNode;
    var goneElement = incompleList.removeChild(parentLi);
    compleList.appendChild(goneElement);
};

var li = incompleList.getElementsByTagName('li');

for (var i = 0; i < incompleList.children.length; i++) {
    var link = li[i];
    var liCheckArray = link.getElementsByTagName('input');
    var liCheck = liCheckArray[0];
    liCheck.onchange = removeMeandAppendMe;
}

When i change my code to the following i get the error "Failed to execute 'removeChild' on 'Node': parameter 1 is not of type 'Node'".

function removeMeandAppendMe(fromList, toList) {
    var parentLi = this.parentNode;
    var goneElement = fromList.removeChild(parentLi);
    toList.appendChild(goneElement);
}

var li = incompleList.getElementsByTagName('li');

for (var i = 0; i < incompleList.children.length; i++) {
    var link = li[i];
    var liCheckArray = link.getElementsByTagName('input');
    var liCheck = liCheckArray[0];
    liCheck.onchange = removeMeandAppendMe(incompleList, compleList);
}

What bothers me, is the fact that the code runs well when my removeMeandAppendMe-function is without parameters and doesnt work with parameters. Can anyone tell my why and where my mistake is? Thank you.

(I'm aware of the blur-problem discussed here: Failed to execute 'removeChild' on 'Node')

Answer

vsahu picture vsahu · Oct 20, 2016

First, as Pointy mentioned, you do need to wrap your call to RemoveMeandAppendMe(incompleList, compleList) in an anonymous function so that it is not invoked prematurely.

Taking that into account, you are receiving this error because of what the value of this is the case of each function invocation. When calling RemoveMeandAppendMe(), this is an HTMLInputElement object, but when calling RemoveMeandAppendMe(incompleList, compleList), this is the Window object, and so this.parentNode is undefined (and thus "not of type 'Node'", which is why you're seeing that error message).

There are a lot of subtleties to this question: what this refers to, and also how different 'function' declarations are treated (lots of discussion here). Just changing the way RemoveMeandAppendMe(incompleList, compleList) is declared doesn't resolve the issue either.

In a way, your question boils down to "Why does this refer to the Window object for the parameterized function call, but an HTMLInputElement object for the non-parameterized function call?" I believe that in this case, this is because, when we wrap the invocation of the parameterized function call in an anonymous function (like so: liCheck.onchange = function(){removeMeandAppendMe(incompleList, compleList);};), removeMeandAppendMe has no 'local' owner, so the ownership of this function defaults to the global object, Window (reference).

To fix this, you can pass in this to the invocation of removeMeandAppendMe, where this will refer to the checkbox, and then use it as a variable within that parameterized function. I've put all of this in your fiddle where things can be played with by commenting/uncommenting different things. Hope this helped.