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 JavaScript and the DOM (Retiring) Making Changes to the DOM Removing an Element from the DOM

Khem Myrick
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Khem Myrick
Python Web Development Techdegree Graduate 18,701 Points

Remove the list item element stored in firstListItem from the DOM.

Task 3 of this challenge asks that I remove the list item element stored within the variable firstListItem from the DOM. Doing so seems to cause Task 1, "Select the unordered list element and store it in the variable myList" to fail. The only solution I could think of was to try to put tasks 2 and 3 above task 1 so that myList still has an unordered list to work with, but I don't really understand where the unordered list is going to begin with.

index.html
<!DOCTYPE html>
<html>
    <head>
        <title>DOM Manipulation</title>
    </head>
    <link rel="stylesheet" href="style.css" />
    <body>
        <ul>
            <li id="first">First Item</li>
            <li id="second">Second Item</li>
            <li id="third">Third Item</li>
        </ul>
        <script src="app.js"></script>
    </body>
</html>
app.js
let firstListItem = document.querySelector('#first');
document.removeChild(firstListItem);
let myList = document.querySelector('ul');

3 Answers

Steven Parker
Steven Parker
231,248 Points

Here's a few hints:

  • the "firstListItem" is not a direct child of the document
  • there might be a reason the challenge wanted you to define "myList" first
  • don't change the ordering of the code lines

God bless you.

Steven Parker
Steven Parker
231,248 Points

So Khem, we seem to have taken your question pretty far in a different direction, I hope it hasn't been a source of confusion!

Khem Myrick
seal-mask
.a{fill-rule:evenodd;}techdegree seal-36
Khem Myrick
Python Web Development Techdegree Graduate 18,701 Points

I'm sorry. I thought I clicked the "best answer" button awhile ago. Of course, as soon as I saw that I could just apply the method to the variable, it seemed obvious. (I think I was worried I'd be removing the li from my variable, but not from the DOM somehow).

Also, it's fascinating to think about JS reading each line of HTML white space as a node. That might save me some confusion later on. Thanks!

I approached this solution slightly differently than you. Rather than trying to use a query selector to get at the childNode, try using the childNodes[i] method off the myList parent node. Here's a prompt below. Be sure to check the MDN documentation for examples of how to impliment the removeChild element off the parent node. Link to docs is below.

let myList = document.querySelector('ul');
let firstListItem = myList.childNodes[1];
//your code here

https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild

Steven Parker
Steven Parker
231,248 Points

NB: Both uses of "querySelector" are correct in the original code, though your method is also effective.

Fair point, Steven, thank you.

I hadn't tested if using the document.querySelector('#first') to assign let firstListItem still produced the desired result when using node.removeChild(), but it seems to work just fine either way.

Steven Parker
Steven Parker
231,248 Points

BTW — I am curious if you know why you needed myList.childNodes[1] instead of myList.childNodes[0]? And do you know what myList.childNodes[0] actually represents?

For clarity, brevity, and code robustness you might want to use myList.children[0] instead.

TLDR; After some researching, I would agree that myList.children[0] would be a much better choice; Most people think of DOM elements when manipulating the DOM and wouldn't naturally account for text or comment nodes that might be included in Node.childNodes.

BTW — I curious if you know why you needed myList.childNodes[1] instead of myList.childNodes[0]?

Honestly, I had to do more research, and no, I didn't understand why, not really.

And do you know what myList.childNodes[0] actually represents?

From what I've read, childNodes[0] represents any textual content of an element or attribute. In the case of the example above, it would represent any text in the <ul> tag (right?), which is none. What I'm not sure of is if childNodes[0] is always reserved for text. I'm also not sure if there is a reserved childNodes index position for comments. I'd be interested to know more about that, however.

A bit spoilery ahead!

I chose childNodes[i] as part of my response because the MDN docs seem to rely on Nodes as the element from which to invoke removeChild() and not Element. Without fully understanding what a Node was, I was hoping (perhaps naively? :) ) to reinforce the link that myList represented a Node. Using myList.childNodes[i] to get the first list item would demonstrate it was a Node, and that any of it's children were also Nodes (else why name the property childNodes?). After making this mental connection, the removeChild() docs I linked to represent the removeChild() method as Node.removeChild(), implying that it can be called off of a Node. If the OP had already made the connection that myList represented a Node, they may have arrived at the idea that you could invoke removeChild() on myList to remove the desired Node.

That was my train of thought, all without really understanding what a Node was.

But, now I know a little better about what Node is. So, if I'm correct, Node is an interface, one that Elements (among many other DOM API objects) implement? In other words, in the case of this example, because all present elements use the Node interface, you could call both childNodes and removeChild() from any DOM element.

Steven Parker
Steven Parker
231,248 Points

So, myList.childNodes[0] would have been the first item if the <ul> tag had been adjacent to the <li> tag in the HTML file. But since they are on separate lines, it represents the white space in between them as a text node. The fact that just adding or removing white space can change the indexing makes code that relies on node order (without checking it) potentially "brittle". So for most uses, properties that are based on elements instead of nodes will produce more robust code.

ahh...wow.

Yeah, that's pretty brittle. Thanks for prompting me to think more about this.

God bless you and your family.