-2

Below is the code snippet of what is happening. If you type task into the input then just add it three times you can see that when you click on the items added below only the first and third will get the strikethrough. A similar problem would happen with four or five items added.

// View Controller
let UICtrl = (function () {

  let DOMstrings = {
    inputBtn: '#input-btn',
    toDo: '#text-input',
    listContainer: '#to-do-list'
  };

  return {
    getInput: function() {
        return {
            item: document.querySelector(DOMstrings.toDo).value
        };
    },

  addListItem: function(obj) {
      let html, newHtml, element;
      // Create HTML string with placeholder text
      
      element = DOMstrings.listContainer;
              
      if(obj.toDo) {} 
      else {
        return
      };
      html = '<li name= "list-item-task" id= "list-item-%id%" class="list-item-task">%toDo%<ion-icon id="icon-remove" name="close-circle-outline" class="icon-remove animate__animated"></ion-icon></li>';
      
      newHtml = html.replace('%id%', obj.id);
      newHtml = newHtml.replace('%toDo%', obj.toDo);
      newHtml = newHtml.replace('%date%', obj.date);
      
      // Insert the HTML into the DOM
      document.querySelector(element).insertAdjacentHTML('beforeend', newHtml);
  },
  
  jQuery: (function() {
    
     //click list items to add strikethrough
        $(".list-item-task").click(function () {
        
          if ($(this).hasClass("task-complete")) {
            $(this).removeClass("task-complete")
          } else {
            $(this).addClass("task-complete")
          } 
    
        });
  }),

    getDOMstrings: function() {
      return DOMstrings;

    }
  };
  })();

let listCtrl = (function (){

    let Item = function(id, toDo, date) {
    this.id = id;
    this.toDo = toDo;
    this.date = date;
};


  let toDoList = [];
  
  return {
    addItem: function(toDo, date) {
      let newItem, ID;
     
      // Create new ID
      if (toDoList.length > 0) {
        ID = toDoList.length;
    } else {
        ID = 0;
    }
    
    newItem = new Item(ID, toDo, date)
    
    toDoList.push(newItem);

    return newItem;
  
  },
  }
})(); 


let controller = (function (UICtrl, listCtrl) { 
    let DOM = UICtrl.getDOMstrings();

    let setupEventListeners = function() {
      
      document.querySelector(DOM.inputBtn).addEventListener('click', ctrlAddItem);
    };

    let ctrlAddItem = function () {
    
      let input, newItem;  
    
      input = UICtrl.getInput();
      newItem = listCtrl.addItem(input.item, input.date);
      UICtrl.addListItem(newItem);
      UICtrl.jQuery();
    };

    return {
      init: function() {
          setupEventListeners();
      }
  };

  })(UICtrl, listCtrl);
  
controller.init();
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

/*----------------------------------------------*/
/*HEADER*/
/*----------------------------------------------*/
html, 
body {
    background-color: #fff;
    color: #000;
    font-family: 'Lato', sans-serif;
    font-size: 20px;
    font-weight: 300;
    text-rendering: optimizeLegibility;
    overflow-x: hidden;
}

.row {
    background-color: rgba(255, 255, 255, .55);
    width: 100%;
}

.main-nav li {
    color: #000;
    font-family: 'Lato', sans-serif;
    font-size: 20px;
    font-weight: 400;
    display: inline-block;
    border: none;
    width: 20%;
}

.main-nav li:hover {
border-bottom: 2px solid #e67e22;
background: transparent;
}

.input-container {
    text-align: center;
    display: block;
    padding-top: 20px;
}

.input-container {
    background-color: rgb(248, 248, 248);
    text-align: center;
    height: 80px;
    float: inline-block;
}

.text-input {
    width: 37.5%;
    height: 50%;
    font-size: 18px;
    font-family: 'Lato', sans-serif;
    border: 1px solid #b9b9b9;
    border-radius: 5px;
}

.date-input {
    width: 15%;
    height: 50%;
    font-size: 18px;
    font-family: 'Lato', sans-serif;
    border: 1px solid #b9b9b9;
    border-radius: 5px;
}

.btn-add-item {
    height: 40px;
    width: 6.25%;
    font-size: 18px;
    font-family: 'Lato', sans-serif;
    color: #ffb325;
    background-color: transparent;
    border: 2px solid #ffb325;
    border-radius: 5px;
}

.list-container {
    position: relative;
    left: 25%;
    margin-top: 10px;
}

.list-item-task {
    border-radius: 5px;
}

li {
    text-align: center;
    width: 50%;
    display: block;
    border: 1px solid #b9b9b9;
    padding: 10px 30px 10px 30px;
}

li:hover {
    background-color: #ececec;
}

.task-complete {
    text-decoration: line-through;
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" type="text/css" href="style.css">
  </head>
<body>
  <header>    
  </header>
  <div class="input-container">
    <input type="text" id="text-input" class="text-input" placeholder="   Task" required>
    <input type="submit" class="btn-add-item icon" id='input-btn' value='Add Item'></input>
  </div>
  <div class="list-container">
      <ul id='to-do-list'>
        
      </ul>
  </div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="script.js"></script>
</html>

The jQuery code I have is only being applied to every other list item in the HTML. When in the dev tools I can see it register the click event listener, but it does not add the class when needed for some of the items. It will successfully add it to the last item added in a list, but not the item before that.

I realize the issue may lie somewhere else within the code and would appreciate thoughts on what could be causing this.

        $(".list-item-task").click(function () {
        
          if ($(this).hasClass("task-complete")) {
            $(this).removeClass("task-complete")
          } else {
            $(this).addClass("task-complete")
          } 
    
        });

Here is an image showing the issue

Thanks!

SJMiller
  • 11
  • 2
  • 3
    Can you edit the question to include a more complete example of the problem? Since this is just JavaScript you can even create a runnable code snippet to demonstrate so we can observe the problem as it happens. – David Sep 23 '20 at 12:20
  • 2
    It would be very helpful if you could provide us the html and css so we can recreate this. – Carsten Løvbo Andersen Sep 23 '20 at 12:20
  • Please see [mre] and [Stack Snippets](https://meta.stackoverflow.com/q/358992/215552) for more on how to create a runnable code snippet as @David suggests. – Heretic Monkey Sep 23 '20 at 12:23
  • Are you adding items after your code (provided here) has run? `$(".list-item-task").click(` only applies to elements that exist at the time the code runs - if you want it to apply to future elements, then you need to use event delegation. See https://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements – freedomn-m Sep 23 '20 at 12:36

1 Answers1

0

Your code is working as you can see in the example, but you can use $(this).toggleClass("task-complete") to get the same result as your if statement.

Note

If your click event does not fire, you might load the script before the elements has been created.

Demo

$(".list-item-task").click(function() {
  $(this).toggleClass("task-complete")
});
.task-complete {
  text-decoration: line-through;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
  <li class="list-item-task task-complete">1</li>
  <li class="list-item-task">2</li>
  <li class="list-item-task">3</li>
</ul>

Working demo

// View Controller
let UICtrl = (function() {

  let DOMstrings = {
    inputBtn: '#input-btn',
    toDo: '#text-input',
    listContainer: '#to-do-list'
  };

  return {
    getInput: function() {
      return {
        item: document.querySelector(DOMstrings.toDo).value
      };
    },

    addListItem: function(obj) {
      let html, newHtml, element;
      // Create HTML string with placeholder text

      element = DOMstrings.listContainer;

      if (obj.toDo) {} else {
        return
      };
      html = '<li name= "list-item-task" id= "list-item-%id%" class="list-item-task">%toDo%<ion-icon id="icon-remove" name="close-circle-outline" class="icon-remove animate__animated"></ion-icon></li>';

      newHtml = html.replace('%id%', obj.id);
      newHtml = newHtml.replace('%toDo%', obj.toDo);
      newHtml = newHtml.replace('%date%', obj.date);

      // Insert the HTML into the DOM
      document.querySelector(element).insertAdjacentHTML('beforeend', newHtml);
    },

    jQuery: (function() {

      //click list items to add strikethrough

    }),

    getDOMstrings: function() {
      return DOMstrings;

    }
  };
})();

$("#to-do-list").on('click', '.list-item-task', function() {
  $(this).toggleClass("task-complete")
});

let listCtrl = (function() {

  let Item = function(id, toDo, date) {
    this.id = id;
    this.toDo = toDo;
    this.date = date;
  };


  let toDoList = [];

  return {
    addItem: function(toDo, date) {
      let newItem, ID;

      // Create new ID
      if (toDoList.length > 0) {
        ID = toDoList.length;
      } else {
        ID = 0;
      }

      newItem = new Item(ID, toDo, date)

      toDoList.push(newItem);

      return newItem;

    },
  }
})();


let controller = (function(UICtrl, listCtrl) {
  let DOM = UICtrl.getDOMstrings();

  let setupEventListeners = function() {

    document.querySelector(DOM.inputBtn).addEventListener('click', ctrlAddItem);
  };

  let ctrlAddItem = function() {

    let input, newItem;

    input = UICtrl.getInput();
    newItem = listCtrl.addItem(input.item, input.date);
    UICtrl.addListItem(newItem);
    UICtrl.jQuery();
  };

  return {
    init: function() {
      setupEventListeners();
    }
  };

})(UICtrl, listCtrl);

controller.init();
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}


/*----------------------------------------------*/


/*HEADER*/


/*----------------------------------------------*/

html,
body {
  background-color: #fff;
  color: #000;
  font-family: 'Lato', sans-serif;
  font-size: 20px;
  font-weight: 300;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

.row {
  background-color: rgba(255, 255, 255, .55);
  width: 100%;
}

.main-nav li {
  color: #000;
  font-family: 'Lato', sans-serif;
  font-size: 20px;
  font-weight: 400;
  display: inline-block;
  border: none;
  width: 20%;
}

.main-nav li:hover {
  border-bottom: 2px solid #e67e22;
  background: transparent;
}

.input-container {
  text-align: center;
  display: block;
  padding-top: 20px;
}

.input-container {
  background-color: rgb(248, 248, 248);
  text-align: center;
  height: 80px;
  float: inline-block;
}

.text-input {
  width: 37.5%;
  height: 50%;
  font-size: 18px;
  font-family: 'Lato', sans-serif;
  border: 1px solid #b9b9b9;
  border-radius: 5px;
}

.date-input {
  width: 15%;
  height: 50%;
  font-size: 18px;
  font-family: 'Lato', sans-serif;
  border: 1px solid #b9b9b9;
  border-radius: 5px;
}

.btn-add-item {
  height: 40px;
  width: 6.25%;
  font-size: 18px;
  font-family: 'Lato', sans-serif;
  color: #ffb325;
  background-color: transparent;
  border: 2px solid #ffb325;
  border-radius: 5px;
}

.list-container {
  position: relative;
  left: 25%;
  margin-top: 10px;
}

.list-item-task {
  border-radius: 5px;
}

li {
  text-align: center;
  width: 50%;
  display: block;
  border: 1px solid #b9b9b9;
  padding: 10px 30px 10px 30px;
}

li:hover {
  background-color: #ececec;
}

.task-complete {
  text-decoration: line-through;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>
  <header>
  </header>
  <div class="input-container">
    <input type="text" id="text-input" class="text-input" placeholder="   Task" required>
    <input type="submit" class="btn-add-item icon" id='input-btn' value='Add Item'></input>
  </div>
  <div class="list-container">
    <ul id='to-do-list'>

    </ul>
  </div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="script.js"></script>

</html>
Carsten Løvbo Andersen
  • 26,637
  • 10
  • 47
  • 77
  • Why not just wait until the OP produces an MRE? What's the hurry? – Heretic Monkey Sep 23 '20 at 12:25
  • 1
    @HereticMonkey I could ask you why you ask the OP to update the question with relevant information when 2 people have already asked that? – Carsten Løvbo Andersen Sep 23 '20 at 12:30
  • I gave links to relevant help articles and Meta FAQs, which previous commenters had not. The problem with prematurely answering is that a) if the answer is actually the problem, it's been answered before and you've added to the list of duplicate answers, making it harder to find answers and b) if this is not the answer, you confuse the OP by making them think they don't have a problem, giving other potential answerers pause before answering. – Heretic Monkey Sep 23 '20 at 12:37
  • @HereticMonkey I've never stated that the OP code is working, I'm just saying that the code itself work. That is also why I left the note about that the OP might load the script before the elements are created. If you don't agree with my methods you are free to flag the question or downvote it if you like. – Carsten Løvbo Andersen Sep 23 '20 at 12:42
  • I added the code that shows how the issue is working. The addItem function runs the jQuery after the item is added to the DOM, but for some reason the jQuery only effects every other item appropriately. – SJMiller Sep 23 '20 at 18:43
  • @SJMiller I've updated the answer with your code, the problem is that you bind the click event every time you create a new li, so when you have made 2x li then the first li has 2x click events – Carsten Løvbo Andersen Sep 24 '20 at 05:52