Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript DOM Scripting By Example Adding and Removing Names Removing Names

davidmansy
PLUS
davidmansy
Courses Plus Student 16,611 Points

Why creating a ul variable in the ul click event handler?

In the ul click event handler function, ul is already available. Is there a specific reason why you create a local ul variable pointing to the li parent node?

4 Answers

Steven Parker
Steven Parker
231,269 Points

This is a delegated event handler.

You were probably thinking of a direct event handler, where the event target is the same element as the handler was attached to.

In this case, the target will be a BUTTON, as determined by the filter. The li and ul variables are then constructed so that they can be used to call removeChild to eliminate the list item that contains the clicked button.

The main reason for using a delegated handler here is that the buttons and list items are being created and removed by the program, and this one handler will take care of them all, even those created after the handler is set up.

davidmansy
davidmansy
Courses Plus Student 16,611 Points

Thx for your answer Steven!

I am totally ok with using a delegated handler instead of a direct handler.

In this handler function, a local ul variable is created by pointing to the li parent. There is no need to create a ul local variable because the ul is already available globally, it was defined by calling document.getElementById() at the very top of the program and it is the same ul that the handler function is attached to.

If you don't create a local ul variable and just use the global ul in the code, it works. So I was wondering if there was a specific reason I miss about creating this ul local variable.

Steven Parker
Steven Parker
231,269 Points

I can see how it might work using the global ul variable in the handler under the current conditions. But relying on a global variable in the event handler is risky, because the value could have changed after the handler was set up. By traversing the DOM to find the ul which is the button's grandparent, then proper functionality is assured even if the global variable has been re-used.

By defining the global ul as a const, the immediate risk is mitigated, but it's still a "best practice" for maintenance reasons to have the handler operate using only values obtained using the event object.

Hi David,

I think you're asking about this code here?

ul.addEventListener('click', (e) => {
  if (e.target.tagName === 'BUTTON') {
    const li = e.target.parentNode;
    const ul = li.parentNode;
    ul.removeChild(li);
  }
});  

In this particular case, I don't think it was strictly necessary to create the local ul variable. Regardless of which li is retrieved, they all have the same parent. The ul that is retrieved here is the same as the global ul that's already been saved.

Perhaps it was written this way to make the intention more clear. You get the element that you need to remove and then you make sure that you get its parent explicitly. Again, not strictly necessary here.

Maybe it's a useful pattern in a general case. You might be in a situation where the elements you retrieve for removal don't necessarily all have the same parent. In which case, you'd want to get the parent like this example.

You probably don't want to have a bunch of global variables of all the possible parents that you might need to call the removeChild() method on.

davidmansy
PLUS
davidmansy
Courses Plus Student 16,611 Points

I see your point, you mean if the variable ul is assigned to something else after the event handler is added. In this case ul is a const so it will stay consistent (thx ES6), it cannot be reassigned. Traversing the dom from the button to the ul is not a good practice. The day you change your html structure and you don't take care of this code, it will break (but you should have unit tests to see that ;-). So between reusing the global const ul or browsing the dom parent by parent (ie fragile code), I would pick the first solution.

Steven Parker
Steven Parker
231,269 Points

Actually, relying on a global inside an event handler makes the code more "brittle". The const nature of the global ul could be changed at any time by a programmer.

The HTML structure you are referring to that the handler relies on is enforced by the JavaScript code itself as it creates and removes the list items. It will not change except by someone working on this code.

The handler construction with DOM traversal as shown in the video is definitely a "best practice". And from Object Oriented Design perspectives, relying on anything outside of the current scope is almost never a good practice.

David,

A changing html structure would be a good reason for why you would want to do it like in the video.

Once you have the element you need to remove, using .parentNode guarantees that you have its parent. It doesn't matter what the html is. I'm not sure what would be fragile about that.

I'm not sure it's possible to write js code that would be immune to all possible html changes.

Steven,

I noticed that the submit handler is using the global ul variable.

Steven Parker
Steven Parker
231,269 Points

It makes more sense for the submit handler to use the global ul, for several reasons:

  • the relationship between the submit button and the list is not enforced by the code
  • the submit button is not being created or removed in the code
  • the invited list is not in the form or even in the same document section
  • the submit handler is direct, not delegated through the list
  • the submit handler also relies on the global input
davidmansy
PLUS
davidmansy
Courses Plus Student 16,611 Points

Guys,

I see this topic becomes hot :-)

I agree that traversing the dom bottom up to retrieve the parent (here a ul) that you want to use to remove the targeted element is a good practice, so at least we agree on this.

What I don't like is that you use parentNode multiple times because you suppose that the ul will always be the grand parent of the button. If you change the code to wrap the button with another element (and in this case it would be using js but in other apps, it could happen by also changing the html), then you will need to add one more call to parentNode, which is something you easily forget and that will generate a bug.

So usually to retrieve the parent and make it more robust, you would add a class to this parent and then traverse the dom up and check if the retrieved node has the right class and if not continue going up, so using recursion (or use the 'closest' jquery method, if you use jquery).

But here you have already "marked" the parent eg the ul by assigning an id, which is a strong decision in your html structure. So instead of using parentNode as many times as needed based on the hierarchy, I would rather reuse the ul for such an easy example and in this particular case, or to be sure that the ul has not been reassigned (as clearly mentioned by Steven), would again call document.getElementById to retrieve the ul.

But I understand as well your point of view and Steven's point of view, not a big deal for the purpose of this course :-)

Steven Parker
Steven Parker
231,269 Points

No matter what you might do to the structure, you must maintain the creation and removal functions together, since you must still traverse the DOM to find the list item to remove. Using the global ul will always save you only one parent reference, as the li will always be the direct child of the ul.

This small savings is certainly not worthwhile in view of the trade-offs.