Elon Musk
Elon Musk

Reputation: 364

Find all checked checkbox which are dynamically added

I am making a simple to do list app. I want to find which tasks have been checked after added and do a line-through on the specific task. How do I do that?

Binding a change event to each task created seems inefficient. How to I proceed from here?

document.getElementById('taskForm').addEventListener('submit',displayTask);

function displayTask(e){
  let task = document.getElementById('taskInput').value;
  let div = document.createElement('div');

  div.innerHTML = `<input type="checkbox">${task}`

  document.getElementById('taskContainer').appendChild(div)
  e.preventDefault();
}
<form id="taskForm">
  <input type="text" id="taskInput" placeholder="Input task" required>
  <input type="submit" value="Add" >
</form>

<div id="taskContainer"></div>

Upvotes: 0

Views: 512

Answers (6)

bru02
bru02

Reputation: 360

You can do it with one event listener, like so:

document.getElementById('taskForm').addEventListener('submit', displayTask);

function displayTask(e) {
  let task = document.getElementById('taskInput').value;
  let div = document.createElement('div');

  div.innerHTML = `<input type="checkbox">${task}`

  document.getElementById('taskContainer').appendChild(div)
  e.preventDefault();
}
document.getElementById('taskContainer').addEventListener('click', function(e) {
  if (e.target && e.target.nodeName == 'INPUT' && e.target.type == 'checkbox') {
  
    if (e.target.checked) {
      e.target.parentNode.style.textDecoration = 'line-through';

    } else {
      e.target.parentNode.style.textDecoration = '';
    }
  }
});
<form id="taskForm">
  <input type="text" id="taskInput" placeholder="Input task" required>
  <input type="submit" value="Add">
</form>

<div id="taskContainer"></div>

It works by adding a click eventListener to the #taskContainer. When #taskContainer is clicked the JS tests if it is a checkbox, if it is then it adds/removes the line-trough depending of the checkbox state.

But I think you should check out W3school's To Do List. It's a good starting point.
W3school's To Do List in action:

// Create a "close" button and append it to each list item
var myNodelist = document.getElementsByTagName("LI");
var i;
for (i = 0; i < myNodelist.length; i++) {
  var span = document.createElement("SPAN");
  var txt = document.createTextNode("\u00D7");
  span.className = "close";
  span.appendChild(txt);
  myNodelist[i].appendChild(span);
}

// Click on a close button to hide the current list item
var close = document.getElementsByClassName("close");
var i;
for (i = 0; i < close.length; i++) {
  close[i].onclick = function() {
    var div = this.parentElement;
    div.style.display = "none";
  }
}

// Add a "checked" symbol when clicking on a list item
var list = document.querySelector('ul');
list.addEventListener('click', function(ev) {
  if (ev.target.tagName === 'LI') {
    ev.target.classList.toggle('checked');
  }
}, false);

// Create a new list item when clicking on the "Add" button
function newElement() {
  var li = document.createElement("li");
  var inputValue = document.getElementById("myInput").value;
  var t = document.createTextNode(inputValue);
  li.appendChild(t);
  if (inputValue === '') {
    alert("You must write something!");
  } else {
    document.getElementById("myUL").appendChild(li);
  }
  document.getElementById("myInput").value = "";

  var span = document.createElement("SPAN");
  var txt = document.createTextNode("\u00D7");
  span.className = "close";
  span.appendChild(txt);
  li.appendChild(span);

  for (i = 0; i < close.length; i++) {
    close[i].onclick = function() {
      var div = this.parentElement;
      div.style.display = "none";
    }
  }
}
/* Include the padding and border in an element's total width and height */
* {
    box-sizing: border-box;
}

/* Remove margins and padding from the list */
ul {
    margin: 0;
    padding: 0;
}

/* Style the list items */
ul li {
    cursor: pointer;
    position: relative;
    padding: 12px 8px 12px 40px;
    background: #eee;
    font-size: 18px;
    transition: 0.2s;

    /* make the list items unselectable */
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

/* Set all odd list items to a different color (zebra-stripes) */
ul li:nth-child(odd) {
    background: #f9f9f9;
}

/* Darker background-color on hover */
ul li:hover {
    background: #ddd;
}

/* When clicked on, add a background color and strike out text */
ul li.checked {
    background: #888;
    color: #fff;
    text-decoration: line-through;
}

/* Add a "checked" mark when clicked on */
ul li.checked::before {
    content: '';
    position: absolute;
    border-color: #fff;
    border-style: solid;
    border-width: 0 2px 2px 0;
    top: 10px;
    left: 16px;
    transform: rotate(45deg);
    height: 15px;
    width: 7px;
}

/* Style the close button */
.close {
    position: absolute;
    right: 0;
    top: 0;
    padding: 12px 16px 12px 16px;
}

.close:hover {
    background-color: #f44336;
    color: white;
}

/* Style the header */
.header {
    background-color: #f44336;
    padding: 30px 40px;
    color: white;
    text-align: center;
}

/* Clear floats after the header */
.header:after {
    content: "";
    display: table;
    clear: both;
}

/* Style the input */
input {
    margin: 0;
    border: none;
    border-radius: 0;
    width: 75%;
    padding: 10px;
    float: left;
    font-size: 16px;
}

/* Style the "Add" button */
.addBtn {
    padding: 10px;
    width: 25%;
    background: #d9d9d9;
    color: #555;
    float: left;
    text-align: center;
    font-size: 16px;
    cursor: pointer;
    transition: 0.3s;
    border-radius: 0;
}

.addBtn:hover {
    background-color: #bbb;
}
<div id="myDIV" class="header">
  <h2>My To Do List</h2>
  <input type="text" id="myInput" placeholder="Title...">
  <span onclick="newElement()" class="addBtn">Add</span>
</div>

<ul id="myUL">
  <li>Hit the gym</li>
  <li class="checked">Pay bills</li>
  <li>Meet George</li>
  <li>Buy eggs</li>
  <li>Read a book</li>
  <li>Organize office</li>
</ul>

Upvotes: 1

Get Off My Lawn
Get Off My Lawn

Reputation: 36299

You can use toggle on an element's classList to toggle a css class.

Here, after we create the div and add the input, we can grab the input and add an event to it. Within the event we can toggle the class of the parent div which contains the line-through css. This will then add/remove a line through the task.

div.querySelector('input').addEventListener('change', e => {
  e.currentTarget.closest('div').classList.toggle('checked', e.currentTarget.checked)
})

Here it is in action:

document.getElementById('taskForm').addEventListener('submit', displayTask);

function displayTask(e) {
  let task = document.getElementById('taskInput').value;
  let div = document.createElement('div');

  div.innerHTML = `<label><input type="checkbox">${task}</label>`

  div.querySelector('input').addEventListener('change', e => {
    e.currentTarget.closest('div').classList.toggle('checked', e.currentTarget.checked)
  })

  document.getElementById('taskContainer').appendChild(div)
  e.preventDefault();
}
.checked {
  text-decoration: line-through;
}
<form id="taskForm">
  <input type="text" id="taskInput" placeholder="Input task" required>
  <input type="submit" value="Add">
</form>

<div id="taskContainer"></div>

Upvotes: 0

Kaddath
Kaddath

Reputation: 6151

It's not the latest state of the art, but this solution only targets your created elements and won't mess with any other input, checkbox or span...

document.getElementById('taskForm').addEventListener('submit',displayTask);

var taskId = 0;

function lineThroughTask(checkbox, id){
  if(checkbox.checked){
    document.getElementById('taskCheckbox_' + id).className = "taskLined";
  }else{
    document.getElementById('taskCheckbox_' + id).className = "";
  }
}

function displayTask(e){
  let task = document.getElementById('taskInput').value;
  let div = document.createElement('div');

  div.innerHTML = `<input type="checkbox" onclick="lineThroughTask(this, '` + taskId + `');"><span id="taskCheckbox_` + taskId + `">${task}</span>`;
  
  taskId++;

  document.getElementById('taskContainer').appendChild(div)
  e.preventDefault();
}
.taskLined {
    text-decoration: line-through;
}
<form id="taskForm">
  <input type="text" id="taskInput" placeholder="Input task" required>
  <input type="submit" value="Add" >
</form>

<div id="taskContainer"></div>

Upvotes: 1

Alex
Alex

Reputation: 2232

Here is my contribution.

I used an onchange event and wrapped the whole input with a span which get's a class toggled called .strike-through:


document.getElementById('taskForm').addEventListener('submit', displayTask);

function strikeThrough(e) {
  e.target.parentNode.classList.toggle('strike-through');
}

function displayTask(e) {
  let task = document.getElementById('taskInput').value;
  let div = document.createElement('div');

  div.innerHTML = `<span><input type="checkbox" onchange="strikeThrough(event)">${task}</span>`

  document.getElementById('taskContainer').appendChild(div)
  e.preventDefault();
}
.strike-through {
  text-decoration: line-through;
}
<form id="taskForm">
  <input type="text" id="taskInput" placeholder="Input task" required>
  <input type="submit" value="Add">
</form>

<div id="taskContainer"></div>

Upvotes: 1

MajiD
MajiD

Reputation: 2575

give them a name and find all checked :

var checked = document.querySelectorAll('input[name=tasks]:checked');

Upvotes: 0

Alex S.
Alex S.

Reputation: 632

Use querySelectorAll method:

var chkBoxes = document.querySelectorAll('input[type=checkbox]');
for (var i = 0, l = chkBoxes.length; i < l; i++) {

    if (chkBoxes[i].checked) {
      ...
    }
}

Upvotes: 0

Related Questions