Thinking in Code

JavaScript
Updated: May 27, 2021

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.


Reply by email

Monthly Newsletter

Once a month I curate a newletter for designers and developers interested in static sites, CSS and web performance. Check out past issues to get an idea.

Product