5

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')

11
  • Can you create a fiddle showing your problem? Commented Jul 7, 2015 at 20:13
  • what is incompleteList? Where is it assigned? Commented Jul 7, 2015 at 20:15
  • Sure: jsfiddle.net/9uj7zfoL Commented Jul 7, 2015 at 20:16
  • incompleteList and compleList are the ids of the both unordered lists Commented Jul 7, 2015 at 20:17
  • The problem is on the last line. You aren't assigning removeMeandAppendMe, you are invoking it. I would suggest looking into the .bind() function to achieve what you're looking to do. Commented Jul 7, 2015 at 20:24

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

You can not do this:

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); // --> here } 

To assign the whole function as a change handler you should do:

liCheck.onchange = () => removeMeandAppendMe(incompleList, compleList); 

or

liCheck.onchange = removeMeandAppendMe.bind(null, incompleList, compleList); 

1 Comment

Uh, wait, neither of those would be correct. The arrow function will call removeMeandAppendMe without a this value, while removeMeandAppendMe.bind(null, incompleList, compleList); will explicitly set this = null. Why is the function and wrong and then there are two wrong ways to attach it as a handler?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.