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

Hosung Kim
Hosung Kim
11,243 Points

Struggling with local storage

I'm struggling with implementing local storage. Currently my code is taking all of the object.keys and calling the createLI function to create LI elements with the stored keys. What would be the best way for me to setItem values of the LI's children on change (ex: the checkbox is checked, select option is selected, notes added, etc.) and to getItem when the list is compiled from localStorage..? Would I setItem on every Event Listener and getItem in the createLI function?

My code so far:

document.addEventListener('DOMContentLoaded', () => {
  const form = document.getElementById('registrar');
  const input = form.querySelector('input');

  const mainDiv = document.querySelector('.main');
  const ul = document.getElementById('invitedList');

  const div = document.createElement('div');
  const filterLabel = document.createElement('label');
  const filterCheckBox = document.createElement('input');


//Listens to 'Hide those who haven't responded' CHECKBOX. If 'confirm' checkbox is checked, hide 'confirmed' text node/checkbox.
  filterLabel.textContent = "Hide those who have declined or haven't responded";
  filterCheckBox.type = 'checkbox';
  div.appendChild(filterLabel);
  div.appendChild(filterCheckBox);
  mainDiv.insertBefore(div, ul);
  filterCheckBox.addEventListener('change', (e) => {
    const isChecked = e.target.checked;
    const lis = ul.children;
    if (isChecked) {
      for (let i = 0; i < lis.length; i += 1) {
        let li = lis[i];
        if (li.className === 'responded') {
          li.style.display = '';
          li.childNodes[1].style.display = 'none';
        } else {
          li.style.display = 'none';
        }
      }  
    } else {
      for (let i = 0; i < lis.length; i += 1) {
        let li = lis[i];
        li.style.display = '';
        li.childNodes[1].style.display = '';
      }  
    }
  });


//Function creates LI element with appropriate BUTTONS appended
  function createLI(text, value) {
    function createElement(elementName, property, value) {
      const element = document.createElement(elementName);
      element[property] = value;
      return element;
    }

    function appendToLI(elementName, property, value) {
      const element = createElement(elementName, property, value);
      li.appendChild(element);
      return element;
    }

    const li = document.createElement('li');
    appendToLI('span', 'textContent', text);
    appendToLI('label', 'textContent', 'Confirm')
      .appendChild(createElement('input', 'type', 'checkbox'));
    document.createElement('label').textContent = '';
    appendToLI('select', 'type', 'select')
        .appendChild(createElement('option', 'textContent', 'Not responded'))
        .parentNode.appendChild(createElement('option', 'textContent', 'Declined'));
    appendToLI('button', 'textContent', 'edit'); 
    appendToLI('button', 'textContent', 'remove');
    appendToLI('label', 'textContent', 'Notes:')
        .appendChild(createElement('textarea', 'textContent', ''));

    if (supportsLocalStorage()) {
      localStorage.setItem(text, value);
    }

    return li;
  }


//Listens for SUBMIT and calls 'createLI' function to make a new LI
   form.addEventListener('submit', (e) => {
    e.preventDefault();
    const text = input.value;
    const textarea = document.querySelectorAll('textarea')[0]
    if (wrongName()) {
      return;
    } else {
    input.value = '';
    const li = createLI(text);
    ul.appendChild(li);
    cardStyles();
    }
  });


//Function to check if value in TEXT INPUT is blank or if it matches current LI
  function wrongName () {
    let text = input.value;
    let li = ul.children;
    false;
    for (let i = 0; i < li.length; i++) {
      let names = li[i].firstElementChild.textContent;
      if (text === names) {
        alert('That person already exists in the database. Please try another name.');
        return true;
      } else if (text === '') {
        alert('Please enter a name');
        return true;
      }
    }
  }


//Function to change LI styling for Event Listener (form.addEventListener)
  function cardStyles () {
    let textarea = document.querySelectorAll('textarea');
    let correspondence = document.querySelectorAll('select');
    for (let i = 0; i < textarea.length; i++) {
      let notes = textarea[i].parentNode;
      notes.style.marginTop = '1em';
      textarea[i].style.display = 'flex';
      textarea[i].style.marginTop = '0.5em';
      textarea[i].style.borderRadius = '3px';
      textarea[i].style.padding = '.3em';
      correspondence[i].style.display = 'flex';
      correspondence[i].style.marginTop = '1em';
      correspondence[i].style.borderRadius = '3px';
      correspondence[i].style.padding = '.1em';
    }
  }


//Listens to UL. If 'confirm' checkbox is checked: Hide drop down SELECT option. If drop down is set to 'Declined': Hide 'confirm' checkbox + label and lower opacity of that LI to 0.5

  ul.addEventListener('change', (e) => {
    const checkbox = event.target;
    const checked = checkbox.checked;
    const confirm = checkbox.previousSibling;
    const listItem = checkbox.parentNode.parentNode;
    const dropDown = checkbox.parentNode.nextElementSibling;

    //CONFIRM CHECKBOX
    if (e.target.tagName === 'INPUT') {
      if (checked) {
        listItem.className = 'responded';
        confirm.replaceWith('Confirmed');
        dropDown.style.visibility = 'hidden';
      } else {
        listItem.className = '';
        confirm.replaceWith('Confirm');
        dropDown.style.visibility = '';
      }
    }

    //DROPDOWN SELECT
    if (e.target.tagName === 'SELECT') {
      const eachPerson = checkbox.parentNode;
      if (checkbox.value === 'Declined') {
        confirm.style.visibility = 'hidden';
        eachPerson.style.opacity = '0.5';
      } else {
        confirm.style.visibility = '';
        eachPerson.style.opacity = '';
      }
    }
  });


//Listens to buttons on LI. If corresponding buttons are clicked, perform corresponding action

  ul.addEventListener('click', (e) => {
    if (e.target.tagName === 'BUTTON') {
      const button = e.target;
      const li = button.parentNode;
      const ul = li.parentNode;
      const action = button.textContent;
      const nameActions = {
        remove: () => {
          ul.removeChild(li);
          if (supportsLocalStorage()) {
            localStorage.removeItem(li.firstElementChild.textContent);
          }
        },
        edit: () => {
          if (supportsLocalStorage()) {
            localStorage.removeItem(li.firstElementChild.textContent);
          }
          const span = li.firstElementChild;
          const input = document.createElement('input');
          input.type = 'text';
          input.value = span.textContent;
          li.insertBefore(input, span);
          li.removeChild(span);
          button.textContent = 'save';
        },
        save: () => {
          const input = li.firstElementChild;
          const span = document.createElement('span');
          span.textContent = input.value;
          li.insertBefore(span, input);
          li.removeChild(input);
          button.textContent = 'edit';
          if (supportsLocalStorage()) {
            localStorage.setItem(span.textContent, span.value); 
          }
        }
      };

      // select and run action in button's name
      nameActions[action]();
    }   
  });


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

  window.onload = function() {
    if (supportsLocalStorage()) {
      const keys = Object.keys(localStorage);
      if (keys.length >-1) {
        for (let i = 0; i < keys.length; i++) {
          const li = createLI(keys[i], localStorage.getItem(keys[i]));
          ul.appendChild(li);
          cardStyles();
        }
      }
    }
  }

});

1 Answer

Hi

I'm curious too... do you have a repo for this?

Tx Robin