Bummer! You have been redirected as the page you requested could not be found.

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 Sibling Traversal

Hello,

I was doing a challenge under the Javascript and the DOM course.

I could solved the challenge, but I was testing to solve it in different ways.

The challenge task is the following:

A delegated click event listener has been attached to the selected ul element, which is stored in the variable list. The handler is targeting each button in the list. When any one of the buttons is clicked, a class of highlight should be added to the paragraph element immediately preceding that button inside the parent list item element. Add the code to create this behavior on line 5.

My first working solution is:

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

list.addEventListener('click', function(e) {

  if (e.target.tagName == 'BUTTON') {

    let p = e.target.previousElementSibling;

    p.className = 'highlight';  }

});

The second solution is:

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

list.addEventListener('click', function(e) {

  if (e.target.tagName == 'BUTTON') {

     let li = e.target.parentNode;

     let p = li.querySelector('p');

    console.log(p);

    p.className = 'highlight';

  }

});

In the third which is not working, I wanted to use the getElementsByTagName('p') method:

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

list.addEventListener('click', function(e) {

  if (e.target.tagName == 'BUTTON') {

    let li = e.target.parentNode;

    let p = li.getElementsByTagName('p');

    console.log(p);

    p.className = 'highlight';

  }

});

Could someone explain me why I cannot use the getElementsByTagName('p') method here?

after seeing this and copying it i was able to complete the challenge! otherwise i had no idea what m i doin :( does it mean i need to go back and retake the whole chapter of node,child ,parent,previous,next sibling :/ as i am still confused a bit abt the whole concept! any advice peeps would help a great deal1 i am stil beginner i guess after reaching here............ or may be i have to take different approach towards it! do i need to start techdegree or some sort to get a better understanding of it??? thanks in advance

5 Answers

Steven Parker
Steven Parker
243,266 Points

It's because getElementsByTagName returns a collection, not a single element.

Just like when you established list on the top line, you need to add an index to select a single element from the collection.


To format posted code, use the instructions from the Markdown Cheatsheet pop-up found below the "Add an Answer" area. :arrow_heading_down:   Or watch this video on code formatting.

Thank you, I understand now. I also made some research about the HTMLcollection and it makes sense.

It should be a one line solution on line 5.

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

Shaqib, it's always a good thing to redo the courses if you don't fully understand them. If the videos are not concise enough then check the teacher's notes. Google the term too and watch Youtube videos.

This was a huge help for me. I was on the right track but I had a dumb rookie syntax problem. This is what I had.

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

list.addEventListener('click', function(e) {
  if (e.target.tagName == 'BUTTON') {
    let pTag = e.target.previousSibling;
    pTag.className (highlight);
  }
});

After trying various ways and reading for an hour I finally read this and Made the switch to this which works perfectly!!

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

list.addEventListener('click', function(e) {
  if (e.target.tagName == 'BUTTON') {
    let pTag = e.target.previousSibling;
    pTag.className = 'highlight';
  }
});

How is the code in the second solution to the op working if you are using console.log(p); before the node's class attribute is set like so: p.className = 'highlight'; ? I thought it would only return the element <p>lorem ipsum</p> since the <p> element is modified after the console.log() method, but instead when I click a button in the console it returns <p class="highlight">lorem ipsum</p>. I guess I'm wondering how the p.className = 'highlight'; is being hoisted above the console.log(p); when it is being called before the function even adds the class to it. Here is the code (HTML and JS):

<!DOCTYPE html>
<html>
    <head>
        <title>JavaScript and the DOM</title>
    </head>
    <body>
        <section>
            <h1>Making a Webpage Interactive</h1>
            <p>Things to Learn</p>
            <ul>
                <li><p>Lorem Ipsum</p><button>Highlight</button></li>
                <li><p>Lorem Ipsum</p><button>Highlight</button></li>
                <li><p>Lorem Ipsum</p><button>Highlight</button></li>
                <li><p>Lorem Ipsum</p><button>Highlight</button></li>
            </ul>
        </section>
        <script src="app.js"></script>
    </body>
</html>
/*jshint esversion: 6 */

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

list.addEventListener('click', function(e) {

  if (e.target.tagName == 'BUTTON') {

     let li = e.target.parentNode;

     let p = li.querySelector('p');

    console.log(p);

    p.className = 'highlight';

  }

});