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 DOM Scripting By Example Improving the Application Code Next Steps

Joseph Bertino
seal-mask
.a{fill-rule:evenodd;}techdegree
Joseph Bertino
Full Stack JavaScript Techdegree Student 14,652 Points

Working Solution with: (1) Local Storage, (2) Drop Down, (3) Free Text Box, and (4) Rejecting Blank and Duplicate Names!

Here's my solution code!

document.addEventListener('DOMContentLoaded', (e) => {
  // Retrieve core page elements
  const form = document.querySelector('form#registrar');
  const input = document.querySelector('input');
  const ul = document.querySelector('ul#invitedList');

  // Create the RSVP filter
  const div = document.createElement('div')
  const filterLabel = document.createElement('label');
  const filterCheckbox = document.createElement('input');
  filterLabel.textContent = 'Hide People Not Coming';
  filterCheckbox.type = 'checkbox';
  div.appendChild(filterLabel);
  div.appendChild(filterCheckbox);
  const divMain = document.querySelector('div.main');
  divMain.insertBefore(div, ul);

  // Create the p that will display error messages
  const header = document.getElementsByTagName('header')[0];
  const pBad = document.createElement('p');
  pBad.textContent = '';
  pBad.className = "badname";
  pBad.style.color = 'darkred';
  header.appendChild(pBad);

  /////// BEGIN LOCAL STORAGE FUNCTIONALITY
  function supportsLocalStorage() {
    try {
      return 'localStorage' in window && window['localStorage'] !== null;
    } catch (e) {
      return false;
    }
  }

  if (supportsLocalStorage()) {
    var guestList = localStorage.getItem('guestList');

    function getLocalGuestList() {
      if (guestList) {
        // return array of guests
        return JSON.parse(guestList);
      } else {
        return [];
      }
    }

    function addGuestFromLocal(guestArr) {
      var newLI = document.createElement('li');
      newLI.innerHTML = guestArr[0];

      let selectedOpt = newLI.querySelector(`option[value="${guestArr[1]}"]`);
      selectedOpt.selected = true;

      let freetext = newLI.querySelector('input[type="text"]')
      freetext.value = guestArr[2];

      ul.appendChild(newLI);
    }

    // Initialize the List of Guests on window load.
    window.onload = function() {
      // Retrieve the list of guests from local storage 
      // and populate the 
      const loadGuestList = getLocalGuestList();
      loadGuestList.forEach((guest) => {
        addGuestFromLocal(guest);
      });
    }

    window.addEventListener('beforeunload', (e) => {
      // Save all guests from the list to local storage
      // Eliminates the need to update guest list every time there is a change
      const saveGuestList = []
      const guests = ul.children; // Element.children returns an HTMLCollection... make it an array 
      console.log('money');
      [...guests].forEach((guest) => {
        /// Create the array to hold the guest's information
        var guestArray = [guest.innerHTML];

        /// Get the selected RSVP option for the guest
        const selectedOpt = guest.querySelector('select').selectedOptions[0];
        guestArray.push(selectedOpt.value);

        // Get the guest's freetext from <input>
        const freeText = guest.querySelector(`input[type="text"]`)
        guestArray.push(freeText.value);

        saveGuestList.push(guestArray);
      });
      localStorage.setItem('guestList', JSON.stringify(saveGuestList));
    });
  }
  /////// END LOCAL STORAGE FUNCTIONS 

  // Create a list item for a guest
  function createLI(guestName) {

    function addElem(elem, property, text, parent) {
      const newElem = document.createElement(elem);
      newElem[property] = text;
      parent.appendChild(newElem);
      return newElem;
    };

    function addSelectOption(value, parent) {
      const option = document.createElement('option');
      option.value = value.toLowerCase();
      option.text = value;
      parent.appendChild(option);
    }

    const li = document.createElement('li'); 

    addElem('span', 'textContent', guestName, li);
    const select = addElem('select', 'name', 'RSVP', addElem('label', 'textContent', 'RSVP: ', li));
    addSelectOption('Not Responded' ,select);
    addSelectOption('Confirmed' ,select);
    addSelectOption('Declined' ,select);
    addElem('INPUT', 'type', 'text', li);
    addElem('BUTTON', 'textContent', 'Edit', li);
    addElem('BUTTON', 'textContent', 'Remove', li);

    return li;
  };
  /// End Create List Item

  /// Logic for creating (or not) new guest
  form.addEventListener('submit', (e) => {
    e.preventDefault();    
    const inputActions = {
      editPBad: (message) => {
        pBad.textContent = message;
      },
      blockDuplicate: (e) => {
        const names = ul.children;
        return [...names].some((name) => {
          let span = name.querySelector('span');
          if (input.value === span.textContent) {
            return true;
          }
        });
      }
    }

    if (input.value === '') {
      inputActions.editPBad("Guest name must not be blank");
    }
    else if (inputActions.blockDuplicate()) {
      inputActions.editPBad(input.value + ' already invited');
      input.value = ''
    } 
    else {
      inputActions.editPBad('');
      let guestName = input.value;
      input.value = '';
      const li = createLI(guestName);
      ul.appendChild(li);
      }
  });

  // Guest Button Events
  ul.addEventListener('click', (e) => {
    if (e.target.tagName === 'BUTTON') {
      const button = e.target;
      const listItem = e.target.parentNode;
      const ul = listItem.parentNode;
      const nameActions = {
        Remove: () => {
          ul.removeChild(listItem);
        },
        Edit: () => {
          const span = listItem.firstElementChild;
          const input = document.createElement('input');
          input.type = 'text';
          input.value = span.textContent;
          listItem.insertBefore(input, span);
          listItem.removeChild(span);
          button.textContent = 'Save'; 
        },
        Save: () => {
          const input = listItem.firstElementChild;
          const span = document.createElement('span')
          span.textContent = input.value;
          listItem.insertBefore(span,input);
          listItem.removeChild(input);
          button.textContent = 'Edit';
        }         
      };

      const action = button.textContent;
      nameActions[action]();
    }
  });
  /// End Guest Button Events

  /// RSVP Filter Button
  filterCheckbox.addEventListener('change', (e) => {
    const isChecked = e.target.checked;
    const lis = ul.children;
    if (isChecked) {
      [...lis].forEach(li => {
        const optDeclined = li.querySelector('option[value="declined"]');
        if (optDeclined.selected === true) {
          li.style.display = 'none';
        }
      });
    }
    else {
      [...lis].forEach(li => {
        li.style.display = '';
      });
    }
  });

});