JavaScript Demo
Now that we have a UI that looks like a todo app, we need to make it function like a todo app. In this example we are going to use raw JavaScript to explicitly modify our application as we interact with it. This will be in stark contrast to the implicit approach we will take when we do this with React in the next exercise.
Keep an eye on how often user actions directly modify the HTML on the page. You'll see this number drop to zero when we start using React.
What we're starting with
This demo starts off with a few functions already in place. Let's walk through what's already here.
clearInput()- This is a generic, reusable function that takes in aselectorparameter, finds the first matching element, and sets the element's value to an empty string. This direct modification is called a side effect.getTodoText()- This is a helper function that returns the value inside of our text field. Notice how some functions return values and how you can save that return value in a variable.filter()- This function takes in afilterNamestring, and abuttonwhich is a reference to the clicked button.- Remove the
selectedclass from the previously selected element. - Add
selectedto the clicked button. - Set
filterNameto the clicked button'sinnerTextvalue. - Get all of the todos with
querySelectAll, and then loop through them. - Set the
hiddenproperty of each todo based on the filter/state combination.
- Remove the
Writing addTodo Function
We start writing all functions with the function keyword and the name of our function. Functions can take parameters, but in this case we don't need to pass any through, so we follow the function name with an empty (). Everything we want this function to do will then be placed in a set of brackets {}.
function addTodo() {}
Creating a Todo Clone
The first thing we need to do in this function is create a newTodo wish is a clone of an existing Todo.
function addTodo() {
const todo = document.querySelector('.todo');
const newTodo = todo.cloneNode(true);
}
Passing true to our cloneNode means it is a deep clone, so we get a copy of the todo's children as well.
Note that this approach is very fragile, as it requires a todo node to always be present on the page.
Updating the newTodos's text
With this clone created, we need to update the innerText of the node with our todo text, which is returned from getTodoText().
function addTodo() {
const todo = document.querySelector('.todo');
const newTodo = todo.cloneNode(true);
newTodo.querySelector('.title').innerText = getTodoText();
}
We can target a child node by calling querySelector again and asking for the child with the .child class.
Note that if we left off the
()we'd actually be assigning innerText to the 'function' instead of the function return.
Placing the newTodo into the list of todos
Making a clone only stores the clone inside of our variable. If we want to place it back into the DOM, we'll need to insert it manually. For that we can use insertBefore.
This function actually needs to target the parent element, which we can get by calling todo.parentElement and passing parameters of (elementToInsert, elementToInsertBefore).
function addTodo() {
const todo = document.querySelector('.todo');
const newTodo = todo.cloneNode(true);
newTodo.querySelector('.title').innerText = getTodoText();
todo.parentElement.insertBefore(newTodo, todo);
}
Cleanup
Now that our todo has been inserted into the DOM, we can clear the text input and call updateRemaining().
function addTodo() {
...
clearInput('.textfield');
updateRemaining();
}
Note how often we have to reach into the DOM to find nodes, manipulate content, insert back into the DOM and manually change the values in inputs. This is the error prone manipulation that React helps us avoid.
Triggering functions from click events
Now that we have a working addTodo function, we need a way to trigger it when the user is ready. This can be done in two ways.
- We can find the element with
querySelector, then set itsonclickto our function
document.querySelector('.addTodo .submit').onclick = addTodo;
- We can add the function directly to our button in our HTML
<button onclick="addTodo()" class="submit">Add</button>
Today we'll use #2, as this is the way it will work in React as well.