Search code examples
javascriptjquerydomevent-listenerevent-propagation

jQuery/Javascript Can't get the "check" button to strike through an appended list item's name text


Have been trying to create an input that creates a list item typed into the input. Once that newly created item is created, I'm trying to make it possible for the user to press a "check" button and have the title of the item change to strike-through.

I have tried to use event delegation for clicking the button on appended items but can't get it to work!

Any help would be greatly appreciated!

$(function() {
  $(".shopping-list").empty(); //clear the list when the browser is loaded for the first time

  $('#js-shopping-list-form').submit(event => { //submission event

    event.preventDefault() //prevent default submission behavior

    //grab the value written in the add an item input
    const shopItemEntry = $(event.currentTarget).find(
      'input[name="shopping-list-entry"]').val();

    //create a new list item for the new item written in in the input and add it to <ul class="shopping-list">
    $('.shopping-list').append(`<li>
        <span class="shopping-item">${shopItemEntry}</span>
        <div class="shopping-item-controls">
          <button class="shopping-item-toggle">
            <span class="button-label">check</span>
          </button>
          <button class="shopping-item-delete">
            <span class="button-label">delete</span>
          </button>
        </div>
      </li>`);

 //listen for when the user clicks check.  Add strikethrough to text for the item who's button is checked.
    $('.ul').on('click', '.shopping-item', 'shopping-item-controls', '.shopping-item-toggle', function(event) {
      $(this).closest('li.span').toggleClass('shopping-item__checked');
    });

    //listen for when the user clicks delete.  Make the delete remove the item
    $('.shopping-item-delete').click(function(event) {
      this.closest('li').remove(); //remove the shopping item entry
    });


  });
});
* {
  box-sizing: border-box;
}

body {
  font-family: 'Roboto', sans-serif;
}

button,
input[type="text"] {
  padding: 5px;
}

button:hover {
  cursor: pointer;
}

#shopping-list-item {
  width: 250px;
}

.container {
  max-width: 600px;
  margin: 0 auto;
}

.shopping-list {
  list-style: none;
  padding-left: 0;
}

.shopping-list>li {
  margin-bottom: 20px;
  border: 1px solid grey;
  padding: 20px;
}

.shopping-item {
  display: block;
  color: grey;
  font-style: italic;
  font-size: 20px;
  margin-bottom: 15px;
}

.shopping-item-checked {
  text-decoration: line-through;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <title>Shopping List</title>

  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/4.2.0/normalize.min.css">
  <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">

  <link rel="stylesheet" href="main.css">
</head>

<body>

  <div class="container">
    <h1>Shopping List</h1>

    <form id="js-shopping-list-form">
      <label for="shopping-list-entry">Add an item</label>
      <input type="text" name="shopping-list-entry" id="shopping-list-entry" placeholder="e.g., broccoli">
      <button type="submit">Add item</button>
    </form>

    <ul class="shopping-list">

      <li>
        <span class="shopping-item shopping-item__checked">apples</span>
        <div class="shopping-item-controls">
          <button class="shopping-item-toggle">
            <span class="button-label">check</span>
          </button>
          <button class="shopping-item-delete">
            <span class="button-label">delete</span>
          </button>
        </div>
      </li>

      <li>
        <span class="shopping-item">oranges</span>
        <div class="shopping-item-controls">
          <button class="shopping-item-toggle">
            <span class="button-label">check</span>
          </button>
          <button class="shopping-item-delete">
            <span class="button-label">delete</span>
          </button>
        </div>
      </li>
      <li>
        <span class="shopping-item">milk</span>
        <div class="shopping-item-controls">
          <button class="shopping-item-toggle">
            <span class="button-label">check</span>
          </button>
          <button class="shopping-item-delete">
            <span class="button-label">delete</span>
          </button>
        </div>
      </li>
      <li>
        <span class="shopping-item">bread</span>
        <div class="shopping-item-controls">
          <button class="shopping-item-toggle">
            <span class="button-label">check</span>
          </button>
          <button class="shopping-item-delete">
            <span class="button-label">delete</span>
          </button>
        </div>
      </li>
    </ul>
  </div>
  <script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
  <script src="index.js"></script>


</body>

</html>


Solution

  • The class you were adding is not what's defined in the css (.shopping-item__checked vs .shopping-item-checked). The selectors for the event and elements to be manipulated when the event happens were also not correct. The check and delete handlers were declared inside the form submit handler, which meant duplicates where registered each time an item was added to the list. See the updated code below.

    $(function() {
      $(".shopping-list").empty(); //clear the list when the browser is loaded for the first time
    
      $("#js-shopping-list-form").submit(event => {
        //submission event
    
        event.preventDefault(); //prevent default submission behavior
    
        //grab the value written in the add an item input
        const shopItemEntry = $(event.currentTarget)
          .find('input[name="shopping-list-entry"]')
          .val();
    
        //create a new list item for the new item written in in the input and add it to <ul class="shopping-list">
        $(".shopping-list").append(`<li>
            <span class="shopping-item">${shopItemEntry}</span>
            <div class="shopping-item-controls">
              <button class="shopping-item-toggle">
                <span class="button-label">check</span>
              </button>
              <button class="shopping-item-delete">
                <span class="button-label">delete</span>
              </button>
            </div>
          </li>`);
      });
    
      //listen for when the user clicks check.  Add strikethrough to text for the item who's button is checked.
      $(".shopping-list").on("click", ".shopping-item-toggle", function(event) {
        $(this)
          .closest("li")
          .find(".shopping-item")
          .toggleClass("shopping-item__checked");
      });
    
      //listen for when the user clicks delete.  Make the delete remove the item
      $(".shopping-list").on("click", ".shopping-item-delete", function(event) {
        this.closest("li").remove(); //remove the shopping item entry
      });
    });
    * {
      box-sizing: border-box;
    }
    
    body {
      font-family: 'Roboto', sans-serif;
    }
    
    button,
    input[type="text"] {
      padding: 5px;
    }
    
    button:hover {
      cursor: pointer;
    }
    
    #shopping-list-item {
      width: 250px;
    }
    
    .container {
      max-width: 600px;
      margin: 0 auto;
    }
    
    .shopping-list {
      list-style: none;
      padding-left: 0;
    }
    
    .shopping-list>li {
      margin-bottom: 20px;
      border: 1px solid grey;
      padding: 20px;
    }
    
    .shopping-item {
      display: block;
      color: grey;
      font-style: italic;
      font-size: 20px;
      margin-bottom: 15px;
    }
    
    .shopping-item__checked {
      text-decoration: line-through;
    }
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <title>Shopping List</title>
    
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/4.2.0/normalize.min.css">
      <link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
    
      <link rel="stylesheet" href="main.css">
    </head>
    
    <body>
    
      <div class="container">
        <h1>Shopping List</h1>
    
        <form id="js-shopping-list-form">
          <label for="shopping-list-entry">Add an item</label>
          <input type="text" name="shopping-list-entry" id="shopping-list-entry" placeholder="e.g., broccoli">
          <button type="submit">Add item</button>
        </form>
    
        <ul class="shopping-list">
    
          <li>
            <span class="shopping-item shopping-item__checked">apples</span>
            <div class="shopping-item-controls">
              <button class="shopping-item-toggle">
                <span class="button-label">check</span>
              </button>
              <button class="shopping-item-delete">
                <span class="button-label">delete</span>
              </button>
            </div>
          </li>
    
          <li>
            <span class="shopping-item">oranges</span>
            <div class="shopping-item-controls">
              <button class="shopping-item-toggle">
                <span class="button-label">check</span>
              </button>
              <button class="shopping-item-delete">
                <span class="button-label">delete</span>
              </button>
            </div>
          </li>
          <li>
            <span class="shopping-item">milk</span>
            <div class="shopping-item-controls">
              <button class="shopping-item-toggle">
                <span class="button-label">check</span>
              </button>
              <button class="shopping-item-delete">
                <span class="button-label">delete</span>
              </button>
            </div>
          </li>
          <li>
            <span class="shopping-item">bread</span>
            <div class="shopping-item-controls">
              <button class="shopping-item-toggle">
                <span class="button-label">check</span>
              </button>
              <button class="shopping-item-delete">
                <span class="button-label">delete</span>
              </button>
            </div>
          </li>
        </ul>
      </div>
      <script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
      <script src="index.js"></script>
    
    
    </body>
    
    </html>