Vue TodoList with Laravel API

by emredipi

HTML

<div id="app">
  <h2>Todos:</h2>
  <div class="loader" v-if="loading"></div>
  <input type="text" v-model="newtodo" v-on:keyup.enter="addNewTodo" class="newtodo">
  <button v-on:click="addNewTodo">
    Add
  </button>
  <ol>
    <li v-for="todo in todos">
      <label>
        <input type="checkbox" v-on:change="toggle(todo)" v-bind:checked="todo.done">
        <del v-if="todo.done">
          {{ todo.text }}
        </del>
        <span v-else>
          {{ todo.text }}
        </span>
      </label>
      <button v-on:click="deleteTodo(todo)" class="delete">
        X
      </button>
    </li>
  </ol>
</div>

CSS

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

del {
  color: rgba(0, 0, 0, 0.3);
}

.loader {
  border: 4px solid #f3f3f3;
  border-top: 4px solid #3498db;
  border-radius: 50%;
  width: 30px;
  height: 30px;
  animation: spin 0.5s linear infinite;
  position: absolute;
  top: 30px;
  right: 30px;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }

  100% {
    transform: rotate(360deg);
  }
}

input[type=checkbox] {
  display: none;
}

input[type=text] {
  height: 20px;
  padding: 5px;
  font-size: 15px;
}

button {
  color: white;
  background-color: green;
  border: 0px;
  border-radius: 15%;
  padding: 5px 10px 5px 10px;
  box-shadow: black 0px 2px 0px 0px;
  outline: none;
}

button:active {
  box-shadow: black 0px 0px 0px 0px;
  transform: translateY(2px);
}

button.delete {
  background-color: #ec3333;
}

Vue

new Vue({
  el: "#app",
  data: {
  	newtodo:"",
    todos:[],
    loading:false
  },
  mounted(){
  	this.loading=true;
  	fetch("https://todoapp.spider/api/todo")
    .then(r=>r.json())
    .then(response=>{
    	this.todos=response;
      this.loading=false;
    }).catch(()=>{
    	this.loading=false;
    });
  },
  methods: {
  	addNewTodo(){
    	if(this.newtodo!=""){
        this.loading=true;
        fetch("https://todoapp.spider/api/todo/",{
          "method":"POST",
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            "done":false,
            "text":this.newtodo
          }),
        })
          .then(r=>r.json())
          .then(response=>{
            this.todos.push(response);
            this.newtodo="";
            this.loading = false;
        });
      }
    },
    deleteTodo(todo){
    	this.loading=true;
      fetch("https://todoapp.spider/api/todo/"+todo.id,{
        "method":"DELETE",
      })
        .then(response=>{
        	this.todos=this.todos.filter(t=>t.id!=todo.id);
	        this.loading = false;
      });
    },
    toggle: function(todo){
    	if(!this.loading){
      	this.loading=true;
        fetch("https://todoapp.spider/api/todo/"+todo.id,{
          method: 'PUT',
            headers: {
              'Content-Type': 'application/json',
            },
            body: JSON.stringify({
              "done":!todo.done
            }),
        })
        .then(r=>r.json())
        .then(response=>{
            todo.done = response.done
            this.loading = false;
        });
      }
    }
  }
})