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

Need help, stuck with this challenge... attempting to remove buttons

The mini project here is to create a list of items that can be changed, moved up and down...

THE CHALLENGE...

Remove the 'unused' 'UP' button & 'DOWN' button..

I managed to do that(not the best way too much code), I'm trying to have the buttons update every time something changes in the list. but i am struggling with this.

I have been at this for a long long time, I do not think I am understanding it at all.

also i realised if I put the hideUnusedButtons() inside the event listener that moves the items, the 'down' is removed and continues to show as 'hidden' as the items move UP and DOWN- I don't understand this at all.

Here is my workspace, the bit i am working on is at the bottom of 'app.js' File , comments showing what I am attempting to do.

https://w.trhou.se/dyykz8208q

Many thanks

1 Answer

KRIS NIKOLAISEN
KRIS NIKOLAISEN
54,370 Points

You do have quite a bit of code. Let's start with your hideUnusedButtons() function. If you run the code and check the console you will see

Cannot read property 'parentNode' of null at hideUnusedButtons (app.js:239)

null is what is assigned here:

let firstButtonUp = listKids[0].firstElementChild.querySelector('.up');

because listKids[0].firstElementChild refers to the first list item's down button and since there are no descendants for this down button, there is nothing to match using querySelector so the method returns null. You can fix this by eliminating firstElementChild:

let firstButtonUp = listKids[0].querySelector('.up');

Then querySelector will match any of the descendants of the list item with the class up. More on this later.

The hideUnusedButtons() function should:

1) Show all the buttons

2) Hide the first list item's up button

3) Hide the last list item's down button

For step 1

In you code you use two loops: one for the list items, then another for the list item's buttons. You could simplify by just selecting all of the list's buttons. Then you would only need one loop.

let buttonsGalore = ul.getElementsByTagName('button')

for (let i = 0 ; i < buttonsGalore.length ; i++) {
    buttonsGalore[i].style.visibility = 'visible'
}

Here the ul is used instead of the individual list items.

For Step 2

You had this code but you commented it out. You could eliminate the firstButtonUp variable and write it all in one line

listKids[0].querySelector('.up').style.visibility = 'hidden'

For step 3

You also had this code but commented it out. Similar to step 2 you could eliminate lastButton

 listKids[listKids.length-1].querySelector('.down').style.visibility = 'hidden'

You will want to check if there are list items before attempting to set any properties so one version of the hideUnusedButtons() function might look like this:

function hideUnusedButtons() {    

    let listKids = ul.children;
    let buttonsGalore = ul.getElementsByTagName('button')

    for (let i = 0 ; i < buttonsGalore.length ; i++) {
        buttonsGalore[i].style.visibility = 'visible'
     }

     if (listKids.length > 0) {
         listKids[0].querySelector('.up').style.visibility = 'hidden'
         listKids[listKids.length-1].querySelector('.down').style.visibility = 'hidden'
    }

};

You could also remove the listKids variable and use firstElementChild and lastElementChild instead:

function hideUnusedButtons() {    

    let buttonsGalore = ul.getElementsByTagName('button')

    for (let i = 0 ; i < buttonsGalore.length ; i++) {
        buttonsGalore[i].style.visibility = 'visible'
     }

     if (ul.children.length > 0) {
         ul.firstElementChild.querySelector('.up').style.visibility = 'hidden'
         ul.lastElementChild.querySelector('.down').style.visibility = 'hidden'
    }

};

You should then be able to call this function after an item is added, removed, or moved up or down the list and check the behavior.

You are an angel! thank you so much for your time and excellent explanation!!