Create a small to-do app including Vue from CDN

Let us create a small example to-do app using Vue from CDN. There is not going to be any backend for this application.

Create basic structure

The basic structure just has two files - index.html and main.js.

<!-- index.html -->
<html>
  <body>
    <div id="app">
      <h5>Hello, {{ name }}</h5>
      <h1>Your To Dos</h1>
    </div>
    <script src="https://unpkg.com/vue"></script>
    <script src="./main.js"></script>
  </body>
</html>

Start playing around with Vue in main.js.

console.log("hello world");

new Vue({
  el: "#app",
  data() {
    return {
      name: "World!"
    };
  }
});

Above code is enough to make the application “usable”. Open index.html in your favourite browser that starts with the word for 🔥.

hello-world-vue-cdn

We have not done anything complex here -

  1. Create two files - html and js. Include the JS in HTML
  2. Write a few lines in HTML
  3. Include Vue from CDN in JS and load it
Tell me more about the HTML

One of the lines in HTML is -

<div id="app"></div>

We have just named the div so that we can load Vue here.

Another line is -

<h5>Hello, {{ name }}</h5>

The name variable in brackets {{ name }} tells Vue to load the specific variable name from Vue’s data block. The variable value is included in HTML.

Tell me more about main.js

There’s not much going on at the moment.

We just initiate a new Vue instance using -

new Vue({ el: "#app" });

While the above line specifies that Vue has to be loaded to an element with id app, we did not quite specify the variables yet. That is easily done in data() block.

A data block is one of the basic components in Vue that defines static variables and specifies values for those variables where relevant.

new Vue({
  el: "#app",
  data() {
    return {
      name: "World!"
    };
  }
});

We can also do a simple name: String instead to define a variable but not initialize its value.

That is about it! When you open index.html in a browser you should see a nice page with the name variable populated.

Start coding your To-do

Before you proceed note that you would have to refresh your browser to see changes each time.

Add todos

We will use a different variable for todos in the Vue block.

console.log("hello world");

new Vue({
  el: "#app",
  data() {
    return {
      name: "World!",
      todos: ["save forests", "burn asteroids to the ground"]
    };
  }
});

We will include todos in the main.html as earlier, but we will take it to the next level. Let us use a v-for directive to loop over elements of todos one by one and print them on the page.

<html>
  <body>
    <div id="app">
      <h5>Hello, {{ name }}</h5>
      <h1>Your To Dos</h1>

      <ul>
        <li v-for="todo in todos">{{ todo }}</li>
      </ul>
    </div>
    <script src="https://unpkg.com/vue"></script>
    <script src="./main.js"></script>
  </body>
</html>

Now your application is somewhat recognizable.

todo-app-cdn-vue-todos

Add an input box and a button to capture new todo’s

Now, let us include an input box to enter new todo’s and a button to submit the todo.

<!-- index.html -->
<!-- other code -->
<h1>Your To Dos</h1>
<p>
  <input type="text" placeholder="Enter new todo" v-model="inputTodo" />
  <button @click="createTodo">Submit</button>
</p>
<!-- other code -->

There are two new Vue components here -

  • v-model is a way of specifying that the text in the text box is bound to a variable within Vue. v-model specifies a “2-way binding” - the text in input box will change if the variable is changed in Javascript and the value of variable within the data block will change when the text within input box is changed
  • @click is a Vue shortcut to bind a Vue method (which is yet to be defined) to the button click event.

We had used {{ name }} and {{ todos }} earlier for binding HTML elements to Vue variables, v-model specifies a two-way binding and accomplish a more ambitious goal. Instead of {{ name }}, we could also do a <p v-model="name"> and the end result will be the same on the page.

Know more about one-way and two-way binding in Vue.

Let’s change main.js to include the changes.

// main.js

console.log("hello world");

new Vue({
  el: "#app",
  data() {
    return {
      name: "World!",
      todos: ["save forests", "burn asteroids to the ground"],
      inputTodo: ""
    };
  },
  methods: {
    createTodo() {
      if (this.inputTodo != "") {
        this.todos.push(this.inputTodo);
        this.inputTodo = "";
      }
    }
  }
});

The first change is quite easy - we included a new variable called inputTodo within data block. Just by using the same name specified in the HTML, we have enabled the HTML element to be bound to this value.

Next, we define another block methods - similar to how data had been defined earlier. Except, methods is an object but data is a function. Remember this distinction - only data of all the Vue components is a function, rest are Javascript objects.

By making data a function, we enable it to have its own variables for each instance of Vue. If you use data as a plain object, the variable values get shared across Vue instances.

Within methods we include a method called createTodo - you may remember that we had specified the same function against the Submit button click event. Within the method we just check whether inputTodo is not empty, and add it to the todos array.

So far we are just manipulating the variables in the data block. But since the input box and the todo list are bound to the variables, any changes to those variables update against the specified HTML. The magic of Vue is to make all this possible without refreshing the browser.

See the changes so far in action - vue-cdn-submit-button-in-action

Include a delete indicator

Let us add a ‘delete’ indicator so that we can let users click it and delete the todo.

<!-- other code -->
<ul>
  <li v-for="todo in todos">
    {{ todo }} &nbsp;
    <span style="cursor: pointer;" @click="deleteTodo(todo)">❌</span>
  </li>
</ul>

<!-- other code -->

The style tag style="cursor: pointer;" will just change the mouse cursor to a pointer when hovered on the ‘delete’ indicator. deleteTodo(todo) will invoke the Vue method and pass todo (which signifies the individual todo in a list of todos) as an argument.

We will define the Vue method in main.js.

// other code
deleteTodo(todo) {
  this.todos.splice(this.todos.indexOf(todo), 1);
}
// other code

In action -

vue-cdn-simple-todo-app-in-action

Complete code

Find the complete code below.

index.html
<!-- index.html -->
<html>
  <body>
    <div id="app">
      <h5>Hello, {{ name }}</h5>
      <h1>Your To Dos</h1>
      <p>
        <input type="text" v-model="inputTodo" placeholder="Enter new todo" />
        <button @click="createTodo">Submit</button>
      </p>
      <ul>
        <li v-for="todo in todos">
          {{ todo }} &nbsp;
          <span style="cursor: pointer;" @click="deleteTodo(todo)">❌</span>
        </li>
      </ul>
    </div>
    <script src="https://unpkg.com/vue"></script>
    <script src="./main.js"></script>
  </body>
</html>
main.js
// main.js
console.log("hello world");

new Vue({
  el: "#app",
  data() {
    return {
      name: "World!",
      todos: ["save forests", "burn asteroids to the ground"],
      inputTodo: ""
    };
  },
  methods: {
    createTodo() {
      if (this.inputTodo != "") {
        this.todos.push(this.inputTodo);
        this.inputTodo = "";
      }
    },

    deleteTodo(todo) {
      this.todos.splice(this.todos.indexOf(todo), 1);
    }
  }
});

Final words

Use CDN for simple use cases where you do not have a build cycle!

See how you can create a similar to-do application using Vue CLI.

comments powered by Disqus