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) Traversing the DOM Sibling Traversal

Greg Schudel
Greg Schudel
4,090 Points

Bummer! One or more of the buttons do not affect their sibling paragraphs.

Not sure how to figure this one out. I am not clear on what they are asking. Do they want you to put a class on the previous paragraph element. Why would you need to put a parentNode property on this problem?

What am I doing wrong here?

app.js
const list = document.getElementsByTagName('ul')[0];

list.addEventListener('click', function(e) {
  if (e.target.tagName == 'BUTTON') {

    let button = event.target.parentNode;
    let buttonParent = button.parentNode;

    if (buttonParent) {
        buttonParent.querySelectorAll('p').className = "highlight";
    }


  }

});
index.html
<!DOCTYPE html>
<html>
    <head>
        <title>JavaScript and the DOM</title>
    </head>
    <link rel="stylesheet" href="style.css" />
    <body>
        <section>
            <h1>Making a Webpage Interactive</h1>
            <p>Things to Learn</p>
            <ul>
                <li><p>Element Selection</p><button>Highlight</button></li>
                <li><p>Events</p><button>Highlight</button></li>
                <li><p>Event Listening</p><button>Highlight</button></li>
                <li><p>DOM Traversal</p><button>Highlight</button></li>
            </ul>
        </section>
        <script src="app.js"></script>
    </body>
</html>
Jaspal Singh
Jaspal Singh
13,525 Points

Hi Greg

first of all use addEventListener on the parent of button that is ul and than use the prevoiuselementsibling on the button which is P element and than change the class of p element.

thanks

6 Answers

Steven Parker
Steven Parker
229,732 Points

You're quite right, you do not need to use the parentNode property. Since the "if" condition has already determined that e.target is the button, you only need to use the previousElementSibling property to access the paragraph.

So the whole thing can be done in one line. :wink:

Zack Lee
PLUS
Zack Lee
Courses Plus Student 17,662 Points

to add what was said, I found a syntax error in your eventListener 'if' statement. you wrote event.target, but passed the event as the variable 'e.' Use "e.target.parentNode" to keep it consistent.

Steven Parker
Steven Parker
229,732 Points

Good point, and it' s easy to do accidentally — I think I've even seen this in one of the instructional videos. But the global "event" variable shouldn't be relied on, particularly when the object was passed in and available that way. You could also use it as "this".

But in this case, all that code will be going away. Right, Greg?

Greg Schudel
Greg Schudel
4,090 Points

But in this case, all that code will be going away. Right, Greg?

how can you do of this in one line of code? I've watched the video and taken Quizzes and there are at least three things you need to do to traverse the DOM as being asked here.

1.) Select the selection

2.) Use the parentNode property of that selection

3.) use the nextElementSibling property along with className to apply the class, right?

This is what I have now... at this point I give up. I'm moving onto something else until I hear back from someone.

const list = document.getElementsByTagName('ul')[0];// why are we selecting the first in the index? Why do we even need this '[0]' ?

list.addEventListener('click', function(e) {
  if (e.target.tagName == 'BUTTON') {// why are we using the e.target object again?

    e.target.nextElementSibling.className = 'highlight';

  }
});
Zack Lee
Zack Lee
Courses Plus Student 17,662 Points

You can't use nextElementSibling because <button> is the last child of your <li> tag.

Try using previousElementSibling. Also, if the challange is asking you to use a specific syntax then even if you use more efficient code the challenge may still fail.

Zack Lee
Zack Lee
Courses Plus Student 17,662 Points

Also, to clarify, the "e.target" is used to select the element from which the event derived.

Steven Parker
Steven Parker
229,732 Points

It looks like you've almost got that one-liner solution (no "parentNode" needed)!

But the paragraph comes before the button, so the property you want is the previousElementSibling.

Greg Schudel
Greg Schudel
4,090 Points

This is what I did, FINALLY GOT IT!!!! THANK GOD!!

Couple questions...

const list = document.getElementsByTagName('ul')[0];

list.addEventListener('click', function(e) {
  if (e.target.tagName == 'BUTTON') {

    e.target.previousElementSibling.className = 'highlight';// why do I have to rewrite e.target here in order to call it correctly?

  }
});

Also, to clarify, the "e.target" is used to select the element from which the event derived.

Why can't I just use parentNode property to do that? Does anybody have any other solutions that I could use to do the same thing (even if it causes errors in Treehouse Editor)?

Steven Parker
Steven Parker
229,732 Points

But what element would you get the parentNode property from? Using "e.target" gives you a starting point that you can traverse from.

Your code doesn't rewrite "e.target", it just uses it as a reference to get to the paragraph element that comes before the button. Then you're only changing the className property on that element.

And any working solution would pass the challenge. This just happens to be a particularly concise and efficient one.

Glad to see you solved it! Happy coding!

Greg Schudel
Greg Schudel
4,090 Points

Another question for this code. Was taking this challenge again and noticed some other questions.

const list = document.getElementsByTagName('ul')[0];

list.addEventListener('click', function(e) {
  if (e.target.tagName == 'BUTTON') {

    e.target.previousElementSibling.className = 'highlight';
/* why do I have to rewrite e.target here in order to call it correctly? Should this work just fine?

previousElementSibling.className = 'highlight';

*/



  }
});
Zack Lee
Zack Lee
Courses Plus Student 17,662 Points

No, previousElementSibling needs to be in reference to something. Try that snipet, you'll get an error. e.target specifies where the program should start looking in the DOM

Steven Parker
Steven Parker
229,732 Points

The name "previousElementSibling" is an element property. By itself it is an undefined reference and causes an error.

Greg Schudel
Greg Schudel
4,090 Points

The name "previousElementSibling" is an element property. By itself it is an undefined reference and causes an error.

So, even within functions that have conditions on them, when I'm trying to manipulate the DOM, I ALWAYS have to specify where to look in the DOM? OR is that too general a question to ask for something this specific?

Steven Parker
Steven Parker
229,732 Points

I think it's fair to say in general you will always need a DOM component to start with in order to make use of traversal properties or methods.

And a condition of an "if" statement doesn't have any effect on the code in the associated code block other than to determine if it will be executed at all.