JavaScript JavaScript and the DOM Traversing the DOM Getting the First and Last Child

Ben S
Ben S
5,562 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,562 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
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

L Haney
L Haney
Full Stack JavaScript Techdegree Student 9,070 Points

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