Harry Cresswell

Practical JavaScript – Thinking in Code

This is Part 6 of my notes on Gordon Zhu’s Practical JavaScript.

Building a todo app v.6.0

In version 6 we’ll work on 1 feature which toggles todos as complete or incomplete.

You can see how this works in the finished app here.

In the example, use the chevron to the left of the input box to toggle the todos you create.

You’ll notice a few cases, if everything is false (items are incomplete) and you click toggle, everything will be true. If some of the items are true (complete), toggle will make the rest true too.

The only case it will make every todo false (incomplete) is when all items are true (complete). In every other case, clicking the toggle button will make all todo items true.

We can represent this in our requirements.

Requirements

  • .toggleAll: If everything’s true, make everything false.
  • .toggleAll: Otherwise, make everything true.

Step 1: If everything’s true, make everything false

Our first step is to work on a solution where if everything is true make everything false.

We want to do this in a new method called toggleAll.

toggleAll: function() {
  
  // If everything’s true, make everything false

}


Comparing completedTodos to totalTodos

To make this happen we could use an if statement and count the the number of completedTodos, to see if it equals the number of totalTodos.

If that returns true, we’d know we we’d met the first condition.


toggleAll: function() {
  
  // If everything’s true
  
  if (completedTodos === totalTodos) {
    
    // Make everything false
  
  }

}


Setting the required variables

The problem now is that the variables completedTodos and totalTodos don’t exist yet, so we need to create those next.

toggleAll: function() {
  
  var totalTodos = this.todos.length;
  
  var completedTodos = 0;

  
  // If everything’s true
  
  if (completedTodos === totalTodos) {
    
    // Make everything false
  
  }

}

```

For our `totalTodos` variable, we can use `this.todos.length` to check the number of items in our todo list, so this works great.

`completedTodos` is harder to get. So it’s a safe assumption to start with 0, meaning we have zero completed todos. Then we can look through all the items in our todo list to see how many are completed. If we see a todo is completed we can increase the value of `completedTodos` by 1. To make this happen we can use a `for` loop, which loops through all our items.

### Looping through todos

In the first part of our `for` loop we can use a variable  `i = 0` again as a counter. We want to keep going whilst `i` is less than the `totalTodos`, then increment `i`  by 1 using `i++`. This will loop through our todos.

```

toggleAll: function() {
  
  var totalTodos = this.todos.length;
  
  var completedTodos = 0;

  
  // Count number of completed todos
  
  for (var i = 0; i < totalTodos; i++ ) {

  

  }
  
  // If everything’s true
  
  if (completedTodos === totalTodos) {
    
    // Make everything false
  
  }

}


Check if todo is completed, update completedTodos variable

Then we want to look at each todo item in our array. Using if we can check to see if a specific todo is completed with this.todos[i].completed === true.

And then with completedTodos++, increment completedTodos by 1 if the statement is true.

toggleAll: function() {
  
  var totalTodos = this.todos.length;
  
  var completedTodos = 0;

  
  // Count number of completed todos
  
  for (var i = 0; i < totalTodos; i++ ) {
    
    if (this.todos[i].completed === true) {
      
      completedTodos++
    
    }
  
  }
  
  // If everything’s true
  
  if (completedTodos === totalTodos) {
    
    // Make everything false
  
  }

}

```

This code will go through and return the number of todos that are completed, updating the value in our `completedTodos` variable with the number of completed todos.

### Make false if all todos are true

To make everything `false` if all our todos are set to `true`, we can use the exact same `for` loop as before.

This time using `this.todos[i].completed = false;` to set all todos to `false`, if the number of `completedTodos` is equal to the number of `totalTodos`.


toggleAll: function() {

var totalTodos = this.todos.length;

var completedTodos = 0;


// Count number of completed todos

for (var i = 0; i < totalTodos; i++ ) {

if (this.todos[i].completed === true) {

completedTodos++

}

}

// Case 1: If everything’s true, make everything false

if (completedTodos === totalTodos) {

for (var i = 0; i < totalTodos; i++) {

this.todos[i].completed = false;

}

} 
} 
```

Understanding the code

So first we check to see if the number of completedTodos is the same as the number of totalTodos. If that returns true, then we’ll go through and make all the items false.

In order to get the number of completedTodos in the first place, we use a for loop to count through our todos and check to see if completed is set to true, in which case we would update the number in our completedTodos variable.

Test the code in the console

Now we can test the code to see if it’s working correctly. In the console add 2 new todos.


todoList.addTodo('first');

todoList.addTodo('second');

```

This will return:


My Todos:
 ( ) first
 ( ) second



Now toggle those 2 todos to completed with `todoList.toggleCompleted(0);` and `todoList.toggleCompleted(1);` to return:


My Todos:
 (x) first 
(x) second 
```

Finally, use todoList.toggleAll(); to toggle both todos to false, in other words back to incompleted:

My Todos:

( ) first

( ) second


That wraps up the first requirement of our v.6.0 app.

Step 2: Otherwise, make everything true

The last requirement of version 6 is pretty simple as we’ve done most of the work already.

A big tip here; if you ever find yourself saying “Otherwise”, it’s the perfect time to use an else statement.

toggleAll: function() {
  
  var totalTodos = this.todos.length;
  
  var completedTodos = 0;

  
  // Count number of completed todos
  
  for (var i = 0; i < totalTodos; i++ ) {
    
    if (this.todos[i].completed === true) {
      
      completedTodos++
    
    }
  
  }
  
  // Case 1: If everything’s true, make everything false
  
  if (completedTodos === totalTodos) {
    
    for (var i = 0; i < totalTodos; i++) {
      
      this.todos[i].completed = false;
    
    }
  
    // Case 2: Otherwise, make everything true
  
  } else {
     
    for (var i = 0; i < totalTodos; i++) {
       
      this.todos[i].completed = true;
    
    }
  
  }

}

```

You’ll notice our `else` statement is almost identical to our `if` statement, except in this case we’re making everything `true` instead of `false`.

First we use the `for` loop to count through the todos, and then `this.todos[i].completed = true;` to set the todos to `true`.

### Test the code in the console

As we did before, add some todo items:


todoList.addTodo(‘first’); 
todoList.addTodo(‘second’); 
```

Then run todoList.toggleAll();. This should make everything true.


My Todos:

(x) first

(x) second

```

Run `todoList.toggleAll();` again and it should make everything `false`.


My Todos:
 ( ) first
 ( ) second
 ```

Now test the final case, where some are true and some false to see if toggleAll sets all items to true.

So use todoList.toggleCompleted(0); to toggle the first item to true.


 My Todos:
 (x) first 
( ) second 


Now, run todoList.toggleAll(); again to toggle all to true:


 My Todos: 
(x) first 
(x) second 


Great, our code is working as expected.

v.6.0 Review

In this version we’ve had practice with for loops, accessing different properties on an object, going through items in an array. And linking functions together with this.displayTodos();.

We’ve also looked at keeping track of different variables we need inside for loops. This pulls a lot of the programming concepts we’ve learnt already together into one method.

This version should have given you a better idea of how you think about a program, think like a programer and figure out a feature to systematically write your code.

As we’ve done here you might start by writing out comments, then cases to help guide you as you’re coding.

Commenting your code will help you and others understand it better when you go back to it at a later date.

Weekly Brain—tactics

Brain—tactics contains a bunch of useful tools, articles and tips. No spam ever, just good honest content. Unsubscribe with one click, anytime.