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 Getting the First and Last Child

Ben S
Ben S
5,638 Points

Hiding Up/Down Buttons (My Solution)

First I wrote a function that iterates through each button in each list item and adds the style 'visibility: visible'. The function then sets the style 'visibility: hidden' to the first 'up' button and the last 'down' button.

function refreshBtns () {
    let firstListItem = listUl.firstElementChild;
    let lastListItem = listUl.lastElementChild;
    for (let i = 0; i < lis.length; i++) {
        let btns = lis[i].children;
        for (let j = 0; j < btns.length - 1; j++) {
            btns[j].style.visibility = 'visible';
        }
    }
    firstListItem.querySelector('button.up').style.visibility = 'hidden';
    lastListItem.querySelector('button.down').style.visibility = 'hidden';
}

Then this function is called during the last iteration of the for loop that creates the buttons.

for (let i = 0; i < lis.length; i++) {
    attachListItemButtons(lis[i]);
    if (i === lis.length - 1) {
        refreshBtns();
    }
}

Lastly, the function is called each time there is a click event within listUl or the addItemButton.

listUl.addEventListener('click', (event) => {
    if (event.target.tagName == 'BUTTON') {
        if (event.target.className == 'remove') {
            let li = event.target.parentNode;
            let ul = li.parentNode;
            ul.removeChild(li);
        }
        if (event.target.className == 'up') {
            let li = event.target.parentNode;
            let prevLi = li.previousElementSibling;
            let ul = li.parentNode;
            if (prevLi) {
                ul.insertBefore(li, prevLi);
            }
        }
        if (event.target.className == 'down') {
            let li = event.target.parentNode;
            let nextLi = li.nextElementSibling;
            let ul = li.parentNode;
            if (nextLi) {
                ul.insertBefore(nextLi, li);
            }
        }
        refreshBtns();
    }
});
addItemButton.addEventListener('click', () => {
    let ul = document.getElementsByTagName('ul')[0];
    let li = document.createElement('li');
    li.textContent = addItemInput.value;
    attachListItemButtons(li);
    ul.appendChild(li);
    addItemInput.value = '';
    refreshBtns();
});

Hi Ben,

Thank you for your solution. I had no idea how to figure this out. The refresh is clever.

I have a question though, I don't understand why the -1 after "btns.length - 1" and "lis.length - 1" helps the program to work. I can see it needs it but I can't figure out why aha.

Ben S
Ben S
5,638 Points
btns.length - 1

There are 3 buttons in each li, two of which we want to iterate on. Therefore looping through the length of "btns - 1" will only place the inline style visible on the up and down buttons.

if (i === lis.length - 1) {
        refreshBtns();
    }

This code just says, what until all the list items have buttons created in them, then run the refreshBtns() function. Because i is starting at 0, we know that the last item in lis will be lis -1.

Itzhak Dangoor
seal-mask
.a{fill-rule:evenodd;}techdegree
Itzhak Dangoor
Full Stack JavaScript Techdegree Student 4,077 Points

Great job Ben, Lovely idea.

Two suggestions, be great to have your respond, or anyone.

In the refreshBtns function:

  • It is possible to omit buttons selector and remain the class selector. the code will still run good
  • After any change the first and last item list background colors will remain, as in the video.
    1. Clear all the background color inside the loop
    2. Cut and paste the two lines backgound color from the head of the app.js, adding also if statement only if there is more then one item in the list then activate the colors:

the code will be:

function refreshBtns2 () {
    let firstListItem = listUl.firstElementChild;
    let lastListItem = listUl.lastElementChild;
    for (let i = 0; i < lis.length; i++) {
        lis[i].style.backgroundColor = 'inherit';
        let btns = lis[i].children;
        for (let j = 0; j < btns.length - 1; j++) {
            btns[j].style.visibility = 'visible';
        }
    }

    if(lis.length > 1) {
        firstListItem.style.backgroundColor = 'lightskyblue';
        lastListItem.style.backgroundColor = 'lightsteelblue';
    }
    firstListItem.querySelector('.up').style.visibility = 'hidden';
    lastListItem.querySelector('.down').style.visibility = 'hidden';
}

1 Answer

This code doesn't work. Now neither of the up, down, or remove buttons work.