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;
});
}
}
}
})