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

Sam Bell
Sam Bell
4,410 Points

How do I add and remove a class on multiple parent elements?

Hey

I have setup in my HTML several team members that all have a description about them with a 'read more' button - when you click on this it should reveal more of the description.. However my javascript is only working for the first one and not the rest? Does anyeone know what I am doing wrong? I am looping over the buttons...

Here is my code

var readMoreEl = document.body.querySelectorAll('[data-action="readMore"]');

for (var i = 0; i < readMoreEl.length; i++) {

readMoreEl[i].addEventListener('click', function(event) {

    parentEl = document.body.querySelector('.teamMember .hold');

    if (parentEl.classList.contains('show')) {

        parentEl.classList.remove('show');

    } else {

        parentEl.classList.add('show');
    }
});

}

Dave StSomeWhere
Dave StSomeWhere
19,870 Points

Probably something do with the event.target. Could you post the relevant html and css?

2 Answers

Looks like the problem is this line:

parentEl = document.body.querySelector('.teamMember .hold');

... because querySelector always and only selects the first element that matches those classes.

If you are sure that the count of .teamMember .hold DOM elements will always match up with the count of [data-action="readMore"] DOM elements, you could simply change that line to:

var parentEl = document.body.querySelectorAll('.teamMember .hold')[i];
// don't forget to add "var" here so the variable is scoped to this function instead of bleeding into the global scope!

...but fair warning, that's overly fragile code, since it relies on the coincidence of those 2 counts being the same. It would be better to use the this keyword somehow to connect the specific button clicked with the parent or sibling element you want to manipulate. Without seeing your HTML, I'm guessing here, but it could be something like:

var parentEl = this.parentElement.querySelector('.hold');

This code takes whatever the clicked-on element was, finds its specific parent element (I'm assuming that's the .teamMember container), then finds its first child element with a class="hold" attribute. Since, in this case, you're scoping the .querySelector to the parentElement, it will only look within that branch of the DOM tree for that element, not across the whole document (<html> tag).

I hope this makes sense to you and helps you understand DOM traversal a little better!

Sam Bell
Sam Bell
4,410 Points

Thanks so much! That worked!

Seth Kroger
Seth Kroger
56,413 Points

I think the issue is when you select parentEl with document.querySelector it's selecting the first element with those two classes, not the parent element for the button. You need a way to distinguish those from each other, or a different way of selecting the element, so the click handler can show the right one.