JavaScript DOM Scripting By Example Improving the Application Code Next Steps

Steve Gallant
Steve Gallant
14,169 Points

interacting with HTML retreived from localStorage (via JSON)

Hello there, I've managed to get most of the enhancements for this RSVP app done on my own, but having trouble with localStorage. I'm able to save the ul using JSON and then pull it back up when the page is re-loaded. However, the loaded LI's are not interactive, i.e. there don't appear to be any eventListeners active on their child elements (checkbox, buttons, etc). Furthermore, adding a new invitee via the main input field, it doesn't appear in the ul with the pre-loaded invitees from localStorage.

I think I'm almost there, any tips would be appreciated. Thanks! Steve

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>RSVP App</title>
  <link href="https://fonts.googleapis.com/css?family=Courgette" rel="stylesheet">
  <link href="https://fonts.googleapis.com/css?family=Lato:400,700" rel="stylesheet">
  <link href="css/style.css" rel="stylesheet">
</head>
<body>
  <div class="wrapper">
    <header>
      <h1>RSVP</h1>
      <p>A Treehouse App</p>
      <form id="registrar">
        <input type="text" name="name" placeholder="Invite Someone">
        <button type="submit" name="submit" value="submit">Submit</button>
      </form>
    </header>

    <div class="main">  
      <h2>Invitees</h2>
      <ul id="invitedList"></ul>    
    </div>
  </div>
  <script type="text/javascript" src="app.js"></script>
</body>
</html>
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');


  filterLabel.textContent = "Hide those who haven't responded";
  filterCheckBox.type = 'checkbox';
  div.appendChild(filterLabel);
  div.appendChild(filterCheckBox);
  mainDiv.insertBefore(div, ul);

  if (localStorage.invitees) {
    ul.outerHTML = JSON.parse(localStorage.invitees);
  }


  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 = '';
          // Hide the checkbox and label for confirmed invitees when
          // filter is activated
          li.getElementsByTagName('label')[0].style.display = 'none';
          // console.log(li.getElementsByTagName('label')[0]);
        } else {
          li.style.display = 'none';
        }
      }
    } else {
      for (let i = 0; i < lis.length; i += 1) {
        let li = lis[i];
        li.style.display = '';
        // Show checkbox and label again when filter is removed
        li.getElementsByTagName('label')[0].style.display = '';
      }
    }
  });

  function createLI(text) {
    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'));
    appendToLI('button', 'textContent', 'edit');
    appendToLI('button', 'textContent', 'remove');
    return li;
  }

  form.addEventListener('submit', (e) => {
    e.preventDefault();
    const text = input.value;
    // disallow duplicate names for invitees
    let duplicate = false;
    if (ul.children.length > 0) {
      for (i = 0; i < ul.children.length; i++) {
        if (text.toLowerCase() === ul.children[i].firstElementChild.textContent.toLowerCase()) {
          duplicate = true;
          console.log(duplicate);
        }
      }
    }
    // check for empty string and disallow
    if (text === '') {
      alert('Please enter a valid name');
    } else if (duplicate) {   // check for duplicate names
      alert("Duplicate names not allowed");
      duplicate = false;
    } else {
      input.value = '';
      const li = createLI(text);
      ul.appendChild(li);

      // store ul in localStorage
      console.log(ul.outerHTML);
      localStorage.setItem('invitees', JSON.stringify(ul.outerHTML));
    }

  });

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

    if (checked) {
      listItem.className = 'responded';
      label.childNodes[0].nodeValue = 'Confirmed';
    } else {
      listItem.className = '';
      label.childNodes[0].nodeValue = 'Confirm?';
    }
  });

  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);
        },
        edit: () => {
          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';
        }
      };

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


});

1 Answer

Jay Reyes
Jay Reyes
Python Web Development Techdegree Student 15,923 Points

I'm also experiencing this issue. I'm able to save the invitees and they get loaded.

The problem is that the buttons for the any list item is not interactive.

e: they became interactive for me I just forgot the "()" in nameActionsaction

Steve Gallant
Steve Gallant
14,169 Points

Hi Jay, I'm unclear if you are saying you found the error in my code above? If so, could you please be more specific? I do have the closed parens when calling nameActions...

thanks! Steve