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

Doron Geyer
seal-mask
.a{fill-rule:evenodd;}techdegree
Doron Geyer
Full Stack JavaScript Techdegree Student 9,047 Points

My Solution, with a slight quirk

so my solution works for adding and removing buttons and moving them up and down. The issue I have found is that if I remove items from the top down the last item remaining has only got the remove button ( no up and no down button) great! But if I remove the items from the bottom up, the last item has the remove and down button. Any idea how I can get it to not show the down button.

I tried setting another conditional that says to hide all other buttons if the length of the list collection is 1 but it works sporadically , I tried to set it as a trial if an item is first child && last child element that it disables all the other buttons. Ive spend about 2 hours messing with this but every idea I have seems to produce a new level of headbutting my desk to deal with.

const toggleList = document.getElementById('toggleList');
const listDiv = document.querySelector('.list');
const descriptionInput = document.querySelector('input.description');
const descriptionP = document.querySelector('p.description');
const descriptionButton = document.querySelector('button.description');
const listUL = listDiv.querySelector("ul");
const addItemInput = document.querySelector('input.addItemInput');
const addItemButton = document.querySelector('button.addItemButton');
const lis = listUL.children;
const firstListItem= listUL.firstElementChild;
const ListItem= listUL.lastElementChild;
const allButtons=document.querySelectorAll("button");

function hideButtons(list){
  let firstPosition = listUL.firstElementChild;
  let lastPosition = listUL.lastElementChild;
 for(let i=0;i<list.length;i++){
  let buttonUp= list[i].querySelector("button.up");
  let buttonDown=list[i].querySelector("button.down");
   if(list[i]==firstPosition){
    buttonUp.style.display="none";
   }else if (list[i]==lastPosition){
    buttonDown.style.display="none";
   }
  }  
}
function showButtons(list) {
  let firstPosition = listUL.firstElementChild;
  let lastPosition = listUL.lastElementChild;  
  for(let i = 0 ; i <list.length;i++){
    if(list[i]!=firstPosition && list[i]!=lastPosition){
      let buttonUp= list[i].querySelector("button.up");
      let buttonDown=list[i].querySelector("button.down");
      buttonDown.style.display="";
      buttonUp.style.display="";
    }
  }
}
listDiv.addEventListener("click",(e)=>{
     if(e.target.tagName= "BUTTON"){  
       hideButtons(lis);
       showButtons(lis);
      }   
     });

function attachListItemButtons(li) {
  let up = document.createElement("button");
      up.className="up";
      up.textContent = "up";  
      li.appendChild(up);

  let down = document.createElement("button");
      down.className="down";
      down.textContent = "down";
      li.appendChild(down);

  let remove = document.createElement("button");
      remove.className="remove";
      remove.textContent = "remove";
      li.appendChild(remove);
}


for (let i = 0;i<lis.length; i++){
  attachListItemButtons(lis[i]);
}
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);

      }else if(event.target.className == 'up'){
      let li = event.target.parentNode;
      let ul = li.parentNode;  
      if(li.previousElementSibling){
        ul.insertBefore(li,li.previousElementSibling);
      }             
     }
      if(event.target.className == 'down'){
          let li = event.target.parentNode;
          let nextLi= li.nextElementSibling;
          let ul = li.parentNode;  
          if(nextLi){
            ul.insertBefore(nextLi,li);
        }
    }
  }
});

toggleList.addEventListener('click', () => {
  if (listDiv.style.display == 'none') {
    toggleList.textContent = 'Hide list';
    listDiv.style.display = 'block';
  } else {
    toggleList.textContent = 'Show list';                        
    listDiv.style.display = 'none';
  }                         
});

descriptionButton.addEventListener('click', () => {
   if(descriptionInput.value==""){
  descriptionP.innerHTML ="No list name provided :";
  }else {                                           
  descriptionP.innerHTML = descriptionInput.value + ':';
  descriptionInput.value = '';
  }                       
});

addItemButton.addEventListener('click', () => {
  let ul = document.getElementsByTagName('ul')[0];
  let li = document.createElement('li');
  li.innerHTML = addItemInput.value;
  ul.appendChild(li);
  attachListItemButtons(li);
  addItemInput.value = '';
});
  hideButtons(lis);
  showButtons(lis);

2 Answers

KRIS NIKOLAISEN
KRIS NIKOLAISEN
54,372 Points

Your hideButtons function initially tests if(list[i]==firstPosition), and if true won't test if (list[i]==lastPosition) to see if also true to set the down style. You can reverse these two if blocks and see the opposite effect where removing the items from the bottom up works but removing the items from top to bottom doesn't. To fix this add an initial condition that checks if both first and last are true:

function hideButtons(list){
  let firstPosition = listUL.firstElementChild;
  let lastPosition = listUL.lastElementChild;

  for(let i=0;i<list.length;i++){
    let buttonUp= list[i].querySelector("button.up");
    let buttonDown=list[i].querySelector("button.down");

    if (list[i]==firstPosition && list[i]==lastPosition){
       buttonUp.style.display="none";
       buttonDown.style.display="none";
    } else if(list[i]==firstPosition){
         buttonUp.style.display="none";
    } else if (list[i]==lastPosition){
         buttonDown.style.display="none";
    }
  }  
}

or just have two separate if blocks

function hideButtons(list){
  let firstPosition = listUL.firstElementChild;
  let lastPosition = listUL.lastElementChild;

  for(let i=0;i<list.length;i++){
    let buttonUp= list[i].querySelector("button.up");
    let buttonDown=list[i].querySelector("button.down");

    if(list[i]==firstPosition){
      buttonUp.style.display="none";
    }

    if (list[i]==lastPosition){
      buttonDown.style.display="none";
    }
  }  
}
Doron Geyer
seal-mask
.a{fill-rule:evenodd;}techdegree
Doron Geyer
Full Stack JavaScript Techdegree Student 9,047 Points

Thanks for responding Kris, will give it a shot now that I've had a decent night's sleep. I think I spend too long staring at the problem. Perhaps with a fresh mind, it will be an easy fix.

Going to give your suggestions a try and let you know how it works out.

Cheers, Doron

Doron Geyer
seal-mask
.a{fill-rule:evenodd;}techdegree
Doron Geyer
Full Stack JavaScript Techdegree Student 9,047 Points
if (list[i]==firstPosition && list[i]==lastPosition){
       buttonUp.style.display="none";
       buttonDown.style.display="none";

ok popped it in and it works, which is quite frustrating! as I said in my original post

" tried to set it as a trial if an item is first child && last child element that it disables all the other buttons"

that was one of the first things I tried , guess I was just too tired and muddled to do a decent job of it. sometimes its better to leave it alone and come back to it.

Thanks again.

not sure where to call the function. Nothing is making it work. could someone post finished code so i can compare?