JS 8 - Vue JS Crash Course, SPA Todo List

By Sheldon L Published at 2020-03-12 Updated at 2020-03-12


Get Started

Creat a Project

Run Server

ToDo List App

npm i uuid axios
<template>
  <div id="app">

    <Header />

    <router-view />
  </div>
</template>

<script>
import Header from './components/layout/Header';
export default {
  name: "App",
  components: {
    Header
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}

#nav {
  padding: 30px;
}

#nav a {
  font-weight: bold;
  color: #2c3e50;
}

#nav a.router-link-exact-active {
  color: #42b983;
}
</style>
<template>
  <header class="header">
    <h1>Todo List</h1>
    <div>
      <router-link to="/">Home</router-link>
      |
      <router-link to="/about">About</router-link>
    </div>
  </header>
</template>

<script>
export default {
  name: "Header",
}
</script>

<style scoped>
  .header {
    background: #333;
    color: #fff;
    text-align: center;
    padding: 10px;
  }
  .header a {
    color: #fff;
    padding: 5px;
    text-decoration: none;
  }
</style>
<template>
  <div id="app">
    <Header />
    <AddTodo v-on:add-todo="addTodo"/>
    <Todos v-bind:todos="todos" v-on:del-todo="deleteTodo" />
  </div>
</template>

<script>
  import Todos from '../components/Todos';
  import AddTodo from '../components/AddTodo';

  import axios from 'axios';

  export default {
    name: 'Home',
    components: {
      Todos,
      AddTodo,
    },
    data() {
      return {
        todos: []
      }
    },
    methods: {
      deleteTodo(id) {
        axios.delete(`http://jsonplaceholder.typicode.com/todos/${id}`)
          .then(this.todos = this.todos.filter(todo => todo.id !== id))
          .catch(err => console.log(err))
      },
      addTodo(newTodo) {
        const { title, completed } = newTodo;
        axios.post('http://jsonplaceholder.typicode.com/todos', {
          title,
          completed
        })
          .then(res => this.todos = [...this.todos, newTodo, res.data])
          .catch(err => console.log(err))
      },
      // get todo sample from jsonplaceholder
      created() {
        axios.get('http://jsonplaceholder.typicode.com/todos?_limit=5')
          .then(res => this.todos = res.data)
          .catch(err => console.log(err))
      }
    }
  }
</script>

<style>
  * {
    box-sizing: border-box;
    margin: 0;
    padding: 0%;
  }
  body {
    font-family: Arial, Helvetica, sans-serif;
    line-height: 1.4;
  }
  .btn {
    display: inline-block;
    border: none;
    background: #555;
    color: #fff;
    padding: 7px 20px;
    cursor: pointer;
  }
  .btn:hover {
    background: #666;
  }
</style>
<template>
  <div>
    <div v-bind:key="todo.id" v-for="todo in todos">
      <TodoItem v-bind:todo="todo" v-on:del-todo="$emit('del-todo', todo.id)" />
    </div>
  </div>
</template>

<script>
  import TodoItem from './TodoItem';
  export default {
    name: "Todos",
    components: {
      TodoItem,
    },
    props: ["todos"],
  }
</script>

<style scoped>

</style>
<template>
  <div class="todo-item" v-bind:class="{'is-complete': todo.completed}">
    <p>
      <input type="checkbox" v-on:change="markComplete">
      
      <button @click="$emit('del-todo', todo.id)" class="del"></button>
    </p>
  </div>
</template>

<script>
export default {
  name: "TodoItem",
  props: ["todo"],
  methods: {
    markComplete() {
      this.todo.completed = !this.todo.completed;
    }
  }
}
</script>

<style scoped>
  .todo-item {
    background: #eee;
    padding: 10px;
    border-bottom: 1px #bbb dotted;
  }
  .is-complete {
    text-decoration: line-through;
  }
  .del {
    background: #ff0000;
    color: #fff;
    border: none;
    padding: 5px 9px;
    border-radius: 50%;
    cursor: pointer;
    float: right;
  }
</style>
<template>
  <div>
    <form @submit="addTodo">
      <input type="text" v-model="title" name="title" placeholder="Add Todo...">
      <input type="submit" value="Submit" class="btn">
    </form>
  </div>
</template>

<script>
export default {
  name: "AddTodo",
  data() {
    return {
      title: '',
    }
  },
  methods: {
    addTodo(e) {
      e.preventDefault();  // Environment parameter
      const newTodo = {

        title: this.title,
        completed: false,
      };
      // Send up to parent
      this.$emit('add-todo', newTodo);
      this.title = '';
    //   console.log(this.id);
    }
  },
}
</script>

<style scoped>
  form {
    display: flex;
  }
  input[type="text"] {
    flex: 10;
    padding: 5px;
  }
  input[type="submit"] {
    flex: 2;
  }
</style>