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

My Challenge Solution

My solution involves adding buttonRemover and updateButtons functions which are called at appropriate times. Every time a button is pressed, all buttons in the ul are removed and replaced based on the li position in the ul.

The greatest hurdle to accomplish this was realizing that the list items collection was not being updated when the functions were called. With a global variable declared for the ul, the order of the list was never being updated and passed to the conditionals in the attachListItemButtons function. I fixed this by adding the updatedListItems variable when needed.

I would love some feedback on my method!

const toggleList = document.querySelector('#toggleList');
var listDiv = document.querySelector('div.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');
var allListItems = listUl.children;
var firstListItem = listUl.firstElementChild;  
var lastListItem = listUl.lastElementChild;

// removes all buttons from the current li
function buttonRemover(li) {
    while (li.firstChild !== li.lastChild) {
        li.removeChild(li.lastChild);
    }
}

// adds the up, down, and remove buttons
function attachListItemButtons (li) {
    listDiv = document.querySelector('div.list');
    let updatedListItems = listDiv.querySelector('ul').children; 
    firstItem = updatedListItems[0];  
    lastItem = updatedListItems[updatedListItems.length-1];

    // remove all buttons first
    buttonRemover(updatedListItems[i]);

    let up = document.createElement('button');
    up.className = 'up';
    up.textContent = 'Up';
    if (firstItem !== updatedListItems[i]) {li.appendChild(up);}

    let down = document.createElement('button');
    down.className = 'down';
    down.textContent = 'Down';
    if (lastItem !== updatedListItems[i]) {li.appendChild(down);}

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

// callable function to update the buttons
function updateButtons() {
  let updatedListItems = listDiv.querySelector('ul').children;
  for (i=0; i<updatedListItems.length; i++) {
    attachListItemButtons(updatedListItems[i]);
  }  
}

updateButtons(); // initializes buttons

//  listens for clicks on up, down, and remove and performs task
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 ul = li.parentNode;
                          let prevLi = li.previousElementSibling;
                          if (prevLi) {ul.insertBefore(li,prevLi);
                                      };
                      }
                      if (event.target.className == 'down') {
                          let li = event.target.parentNode;
                          let ul = li.parentNode;
                          let nextLi = li.nextElementSibling;
                          if (nextLi) {
                              let nextNext = nextLi.nextElementSibling;
                              ul.insertBefore(li,nextNext);
                                      };
                      }
                      updateButtons();
                   }
});

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

// changes the list description
descriptionButton.addEventListener('click', () => {
    descriptionP.textContent = descriptionInput.value + ':';
    descriptionInput.value = '';                               
});

// adds items to the list and calls attachListItemButtons to add their buttons
addItemButton.addEventListener('click', () => {
    let ul = document.getElementsByTagName('ul')[0];                          
    let li = document.createElement('li');
    li.textContent = addItemInput.value;
    ul.appendChild(li);
    attachListItemButtons(li);
    addItemInput.value = '';
    updateButtons();
});

descriptionP.title = 'List Description';