Using Vue to build a... Wait for it... To do-List!
Tags: javascript, vue
Published: 2020-09-07 00:50:45

As we work our way through the Operation Spark curriculum, we are taught several frameworks that can be used to implement the model-view-controller pattern (or something close to it), such as Backbone, Angular, and React. While researching MVC frameworks, I kept hearing about another one that we don't cover, Vue. I decided to do a little independent research on this framework, leading to this blog post, in which I'm going to walk through my attempt at building a to-do list using Vue.

# What is Vue?
As mentioned earlier, Vue is just a framework that can be used to build out user interfaces. It specifically tries to handle an applications view, and it accomplishes this by binding to and controlling specific HTML elements. This binding means that when the bound object is change, the HTML element will also change. To get an idea of what this might look at, lets look at some HTML:
```html
<div id="todoList">
  <h1>To Do List</h1>
</div>
```
as well as our Vue object:
```javascript
const newTodoList = new Vue({
  el: '#todoList',
})
```
Notice that we create a new Vue, then assign it a key of el with a value of #todoList. This tells our view object that it wants to attach itself to the element in our HTML file that has an id of "todoList". Obviously, this binding means nothing without a little more info. We can assign our Vue a data property to pass some of that info along. Our HTML file and JS file now might look something like this:
```html
<div id="todoList">
  <h1>{{title}}</h1>
</div>
```
```javascript
const newTodoList = new Vue({
  el: '#todoList',
  data: {
    title: 'To-do List',
  },
})
```
We have declared our data object and created a "title" property. Notice that we have updated the h1 tag in our HTML file. Similarly to Angular, Vue uses double braces to access properties from our Vue object. In this case, we're accessing the title property from the data object. That's pretty cool, but it doesn't make this a working to do list! To accomplish that, lets add something to our data property that can hold everything we need to accomplish. While we're at it, lets go ahead and make an id property too, so that we can keep track of things on our list. 
```javascript
const newTodoList = new Vue({
  el: '#todoList',
  data: {
    title: 'To-do List',
    id: 0,
    taskList: [],
  },
})
```
So we've got something to hold our tasks in, but how can we add things to it? Lets go back to our html file and build out some functionality to allow that to happen. Maybe an input element and a button that adds the task to our array? Lets see how that might look:
```html
<div id="todoList">
  <h1>{{title}}</h1>
  <ul>
    <input>
    <button>Add Task</button>
  </ul>
</div>
```
Here we've added a ul element, which will hold our list, an input form, and a button. But we're still not there yet, are we? We need to link that form and that button to some things on our Vue object. We also need to display our list somewhere, but we'll get to that later. For now, lets make some changes to our HTML and our code:
```html
<div id="todoList">
  <h1>{{title}}</h1>
  <ul>
    <input v-model="newTask" placeholder='Task description'>
    <button v-on:click = "addTask">Add Task</button>
  </ul>
</div>
```
```javascript
const newTodoList = new Vue({
  el: '#todoList',
  data: {
    title: 'To-do List',
    id: 0,
    taskList: [],
    newTask: '',
  },
  methods: {
    addTask() {
      const newTaskItem = {
        id: this.id,
        text: this.newTask,
      };
      this.taskList.push(newTaskItem);
      this.id++;
      this.newTask = '';
    }
  }
})
```
So here we have built out most of the functionality of our list. Notice that we have added a newTask property to our data object. We then created a two-way data binding to that object in our input form using the "v-model="newTask" directive. V-model is a bit of syntactical sugar that just knows how to update data concerning user events. In this case, as we type into our form, the newTask property will be reassigned to a string of whatever we're typing. We have also added a placeholder that will display when that string is empty. In our button element, we have used the v-on:click="addTask" directive to listen to the dom for a click on our button, and to run the addTask method when it hears that click. Back in our Vue object, we have declared a methods object, and began to define our methods inside of it. It should be no surprise that we have an addTask method. In short, this method creates an object using the newTask and id properties from our view, pushes that object into our taskList array, increments id, and empties the newTask string. So now we have a way to add tasks to our list of tasks, but we haven't started to display them yet. We can essentially think of each task as an individual element inside of our larger todoList element, so lets keep these two components separated using Vue.component. This will allow us to create a reusable vue instance for use inside of a root Vue instance that we created with new Vue, our newToDoList in this case. These next two instances of our HTML and JS will complete our to do list: 
```html
<div id="todoList">
  <h1>{{title}}</h1>
  <ul>
    <todo-item
      v-for="task in taskList"
      v-bind:task="task"
      ></todo-item>
    <input v-model="newTask" placeholder='Task description'>
    <button v-on:click = "addTask">Add Task</button>
  </ul>
</div>
```
```javascript
Vue.component('todo-item', {
  props: ['task'],
  template: '<li>{{ task.text }}</li>'
})
```
Whoa, seems like there's a lot going on there! Lets walk through it. In our HTML, we've declared a todo-item element. We've also created a Vue.component and named it 'todo-item'. The fact that these two have the same name is what allows them to "talk" to each other. We are essentially plugging in as many instances of a vue component as we need to complete our to do list. We use the v-for command in our HTML file to render multiple components. It can almost be though of like a for..of loop, as we loop over our taskList array (again, notice that we have used the phrase 'taskList' in our HTML and JS files to make this link) and refer to each element as a "task". We will render a new component for each "task" in "taskList". Next, we use v-bind:task="task" to bind a value that we're passing through to our component. We combine this with the props:['task'] line to allow us to reference the properties of each task object in our component rendering. Note that the use of task in v-bind:task is completely arbitrary. We could have used v-bind:elephants="task" in our HTML and as long as we set props: ['elephants'] and referenced using elephants.text  in our JS, we would have got the same results. Finally, in our component, we have a template property. this is interpreted as HTML and rendered to our DOM once for every element in our taskList. With this, we should have a working to do list!

# Conclusion
Vue is a framework that can be used to control the view of an application. It has some similarities to React and some similarities to Angular, but is not quite the same as either.