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

oliverchou
oliverchou
20,886 Points

Sharing my solution to the challenge

This is my solution to the challenge, using 2 functions, one of which includes a 2-level for-loop.

const toggleList = document.getElementById('toggleList');
const listDiv = document.querySelector('.list');
const listUl = listDiv.querySelector('ul');

const descriptionP = document.querySelector('p.description');
const descriptionInput =  document.querySelector('input.description')
const descriptionButton = document.querySelector('button.description');

const addItemInput = document.querySelector('input.addItemInput');
const addItemButton = document.querySelector('button.addItemButton');

const lis = listUl.children;

// starts here
function hideEndBtn () {
  listUl.firstElementChild.firstElementChild.style.visibility = 'hidden';
  listUl.lastElementChild.children[1].style.visibility = 'hidden';
}

function showAllBtn () {
  for(let i=0; i<lis.length; i++) {
    for(let j=0; j<lis[0].childElementCount; j++){
      lis[i].children[j].style.visibility = '';
    }
  }
}

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]);
     }
hideEndBtn(); // initially hide the unnecessary button

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);      
      }
    }
    showAllBtn();
    hideEndBtn(); // check whenever move a <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', () => {
  descriptionP.textContent = descriptionInput.value + ':';
  descriptionInput.value = '';
});

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 = '';
  showAllBtn();
  hideEndBtn(); // check whenever add an item
});

2 Answers

I really like the simplicity of your functions! And how you can use them together when the list changes to reset previously hidden buttons as needed. I wrote functions for my answer as well but they are much longer, with a lot of if else statements to get it right in every situation.

I will say that the console throws an error when you delete all of the list items that looks like:

test.js:16 Uncaught TypeError: Cannot read property 'firstElementChild' of null
    at hideEndBtn (test.js:16)
    at HTMLUListElement.<anonymous> (test.js:74)

The error doesn't seem to affect the functionality of the program at all, but you can avoid it by adding an if statement to the first function like so:

function hideEndBtn () {
  if(listUl.firstElementChild) {
    listUl.firstElementChild.firstElementChild.style.visibility = 'hidden';
    listUl.lastElementChild.children[1].style.visibility = 'hidden';
  }
}

Thank you so much for sharing!