0

I am trying to understand the filter method in JavaScript.

I have an array and with a checkbox and a global variable I want to control what to show in the array.

If the checkbox is unchecked and the value of the variable filterTodos is false (false is default), I want to show all the items of the array. If the checkbox is checked and the variable value of variable filterTodos is true, I want to only show the tasks that are not complete. (completed: false)

I know that my code for the filter method is wrong as it's not doing anything, and when the checkbox is unchecked it displays the array multiple times.

This is my code:

let todos = [{
  text: 'Order airline tickets',
  completed: false
}, {
  text: 'Vaccine appointment',
  completed: true
}, {
  text: 'Order Visa',
  completed: true
}, {
  text: 'Book hotell',
  completed: false
}, {
  text: 'Book taxi to airport',
  completed: true
}]

let filterTodos = false

showTodos(todos);

function addTodo(add_todo) {
  let p = document.createElement('p')
  p.textContent = add_todo.text
  document.querySelector('body').appendChild(p)
  let checkBox = document.createElement("input")
  let label = document.createElement("label")
  checkBox.type = "checkbox"
  checkBox.value = addTodo.completed
  document.querySelector('body').appendChild(checkBox)

  //create variable to generate random id for radiobutton
  const id = Math.random().toString(36)

  checkBox.setAttribute("name", id)

  //Switch loop over the completed
  switch (add_todo.completed) {
    case true:
      checkBox.setAttribute("checked", "true") // Mark true button as checked
      break
    case false:
      checkBox.setAttribute("unchecked", "false") // Mark false button as checked
      break
    default:
      break
  }

  document.querySelector('body').appendChild(label)
  label.appendChild(document.createTextNode(add_todo.completed))
}

function showTodos(show_todos) {
  //function to show the whole object
  show_todos.forEach(function(todo) {
    addTodo(todo);
  })
}

function unComplete(uncompleteTodos) {
  unComplete.filter(!todo.completed)

}

function hideCompleted() {
  document.querySelector("#filterTodo").addEventListener('change', function(e) {

    if (document.getElementById('filterTodo').checked) {
      filterTodos = true;
      console.log(filterTodos);
      filterTodos = todos.filter(unComplete)
      unComplete(todos)
    } else {
      filterTodos = false;
      console.log(filterTodos);
      showTodos(todos)

    }
  })
}
<h1>Todos</h1>
<label style="font: bold 1.5em courier !important">
     <input type="checkbox" id="filterTodo" onChange="hideCompleted()">Hide completed
     </label><br><br>
<input id="search-todo" type="text" placeholder="Search todo">
<button id="reset-search" type="reset" value="reset" onclick="window.location.reload()">New search</button>

<div id="todos"></div>
<form action="" id="addTodo">
  <input type="text" name="inputTodo" placeholder="Insert new todo">
  <button>Add Todo</button>
</form>

<script src="js/index2.js"></script>

4
  • You are making a mistake. When the hideCompleted() will be called it will call showTodos() and then it will call addTodo() and hence it will add new items means items will be double Commented Jan 27, 2019 at 16:22
  • You've created all sorts of problems for yourself that a little attention to detail could resolve. First, you have an onChange attribute on the checkbox that calls a function that sets another change handler that does the same thing. Secondly, you use filter() properly in one part of your code, but then try to run a forEach() loop on something that doesnt' exist - that shows up as an error in the console. You can start by fixing those first. Commented Jan 27, 2019 at 16:22
  • function unComplete(uncompleteTodos) { unComplete.filter(!todo.completed) } also not works. You cannot filter the function Commented Jan 27, 2019 at 16:25
  • @RandyCasburn thanks, I didn't know that of the filter function, I have taken away the loop and just use: uncompleteTodos.filter(!todos.completed) and its still faulty. Could you please alter the code, so I understand what I am doing wrong. Commented Jan 27, 2019 at 16:37

2 Answers 2

1

One step to resolve your bug, it's to make your code a minimal verifiable functionality of what you want to do. Then you have a pretty clear picture of what's going on. You can grab a piece of paper write the flux of your program as well.

Breaking down your code we have:

  1. initial assignment of todos array, filterTodos bool control var and showTodos to add them to the page.
  2. function addTodo: add a todo to the page
  3. function showTodos: iterates todos to calling addTodo

By now, we are ok, considering just the flux. Then we have:

  1. function unComplete: just return todos array filtered with completed: false. It does nothing on the HTML
  2. function hideCompleted: onchange event of each HTML element of todo, where if it's:

    -- checked: just call unComplete resulting on 0 changes to the HTML.

    -- unchecked: calls again showTodos adding again all todos to the HTML.

You have many ways to resolve this issue. I'm showing just the maybe stupidest one then you can improve it as your wish:

 
let todos = [{
  text: 'Order airline tickets',
  completed: false
}, {
  text: 'Book taxi to airport',
  completed: true
}]

init();

// ----------

function addTodo(add_todo, index) {
  let checkBox = document.createElement("input")
  checkBox.type = "checkbox"
  checkBox.id = 'chk' + index

  let label = document.createElement("label")
  label.appendChild(checkBox)
  label.innerHTML += add_todo.text

  let li = document.createElement("li")
  li.appendChild(label)

  document.getElementById('todosList').appendChild(li)
  document.getElementById(checkBox.id).checked = add_todo.completed
}

function addAllTodos(show_todos) {
  show_todos.forEach(function(todo, index) {
    addTodo(todo, index);
  })
}

function showTodo(li){
  li.style.display = 'list-item'
}
function hideTodo(li){
  li.style.display = 'none'
}

function showOnlyUncompletedTodo(li) {
  if (li.querySelector('input[type=checkbox]').checked) {
    hideTodo(li)
  }
  else {
    showTodo(li)
  }
}

function hideCompleted() {
  func = this.checked ? showOnlyUncompletedTodo : showTodo
  document.querySelectorAll('#todosList li').forEach(func)
}

function init(){
  document.getElementById("hideCompleted").addEventListener('change', hideCompleted)
  document.getElementById("btnAddTodo").addEventListener('click', function(){
    let todo = {
      text: document.getElementById('inputNewTodo').value,
      completed: false
    }

    todos.push(todo)
    addTodo(todo, todos.length - 1)
  })

  addAllTodos(todos);
}
.todos-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>repl.it</title>
    <link href="style.css" rel="stylesheet" type="text/css" />
  </head>
  <body>

    <h1>Todos</h1>
    <label style="font: bold 1.5em courier !important">
      <input type="checkbox" id="hideCompleted"> Hide completed
    </label><br><br>
    <input id="search-todo" type="text" placeholder="Search todo">
    <button id="reset-search" type="reset" value="reset" onclick="window.location.reload()">New search</button>

    <div id="todos"></div>
    <form id="addTodo" onsubmit="return false">
      <input type="text" id="inputNewTodo" name="inputTodo" placeholder="Insert new todo">
      <button id="btnAddTodo">Add Todo</button>
    </form>
    <br>

    <ul id="todosList" class="todos-list">

    </ul>

     <script src="script.js"></script>
  </body>
</html>

Sign up to request clarification or add additional context in comments.

1 Comment

thanks for your input, but I really need to save it with filter method, but your code gave me some valuable ideas :)
0

Filter method takes all the items of an array and loops through it. For example:

var words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);

Will only return items from the array with length greater than 6.

So i that that you want: completeTodos.filter(todo => todo.completed) it will return only completed todos.

1 Comment

Its the uncompleted todos that are the problem

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.