_examples/tutorial/vuejs-todo-mvc finished, live updates on all clients with the same session id (u can do it with login id for example) and memory storage on the server side, works perfectly and amazing fast, nice vue and iris

Former-commit-id: 0bb930f43e2d70a707d3c6880dc255acd78debf2
This commit is contained in:
Gerasimos (Makis) Maropoulos 2017-12-23 18:11:00 +02:00
parent e1c65d23fb
commit d31b8c5274
2 changed files with 61 additions and 41 deletions

View File

@ -32,7 +32,8 @@
<ul class="todo-list"> <ul class="todo-list">
<li v-for="todo in filteredTodos" class="todo" :key="todo.id" :class="{ completed: todo.completed, editing: todo == editedTodo }"> <li v-for="todo in filteredTodos" class="todo" :key="todo.id" :class="{ completed: todo.completed, editing: todo == editedTodo }">
<div class="view"> <div class="view">
<input class="toggle" type="checkbox" v-model="todo.completed"> <!-- v-model="todo.completed" -->
<input class="toggle" type="checkbox" @click="completeTodo(todo)">
<label @dblclick="editTodo(todo)">{{ todo.title }}</label> <label @dblclick="editTodo(todo)">{{ todo.title }}</label>
<button class="destroy" @click="removeTodo(todo)"></button> <button class="destroy" @click="removeTodo(todo)"></button>
</div> </div>

View File

@ -1,32 +1,35 @@
// Full spec-compliant TodoMVC with Iris // Full spec-compliant TodoMVC with Iris
// and hash-based routing in ~120 effective lines of JavaScript. // and hash-based routing in ~120 effective lines of JavaScript.
// var socket = new Ws("ws://localhost:8080/todos/sync"); var socket = new Ws("ws://localhost:8080/todos/sync");
// socket.On("saved", function () { socket.On("saved", function () {
// console.log("receive: on saved"); // console.log("receive: on saved");
// todoStorage.fetch(); fetchTodos(function (items) {
// }); app.todos = items
});
});
var todos = [];
function fetchTodos(onComplete) {
axios.get("/todos").then(response => {
if (response.data == null) {
return;
}
onComplete(response.data);
});
}
var todoStorage = { var todoStorage = {
fetch: function () { fetch: function () {
axios.get("/todos").then(response => { var todos = [];
if (response.data == null) { fetchTodos(function (items) {
return; for (var i = 0; i < items.length; i++) {
} todos.push(items[i]);
for (var i = 0; i < response.data.length; i++) {
// if (todos.length <=i || todos[i] === null) {
// todos.push(response.data[i]);
// } else {
// todos[i] = response.data[i];
// }
todos.push(response.data[i]);
} }
}); });
return todos;
return todos
}, },
save: function (todos) { save: function (todos) {
axios.post("/todos", JSON.stringify(todos)).then(response => { axios.post("/todos", JSON.stringify(todos)).then(response => {
@ -35,7 +38,7 @@ var todoStorage = {
return; return;
} }
// console.log("send: save"); // console.log("send: save");
// socket.Emit("save") socket.Emit("save")
}); });
} }
} }
@ -62,27 +65,27 @@ var app = new Vue({
// app initial state // app initial state
data: { data: {
todos: todoStorage.fetch(), todos: todoStorage.fetch(),
hasChanges: false,
newTodo: '', newTodo: '',
editedTodo: null, editedTodo: null,
visibility: 'all' visibility: 'all'
}, },
// watch todos change for persistence // we will not use the "watch" as it works with the fields like "hasChanges"
watch: { // and callbacks to make it true but let's keep things very simple as it's just a small getting started.
todos: { // // watch todos change for persistence
handler: function (todos) { // watch: {
// // saved by this client. // todos: {
// if (todos[todos.length - 1].id === 0) { // handler: function (todos) {
// todoStorage.save(todos); // if (app.hasChanges) {
// } else { // todoStorage.save(todos);
// console.log("item cannot be saved, already exists."); // app.hasChanges = false;
// console.log(todos[todos.length - 1]); // }
// }
todoStorage.save(todos); // },
}, // deep: true
deep: true // }
} // },
},
// computed properties // computed properties
// http://vuejs.org/guide/computed.html // http://vuejs.org/guide/computed.html
@ -101,6 +104,7 @@ var app = new Vue({
this.todos.forEach(function (todo) { this.todos.forEach(function (todo) {
todo.completed = value todo.completed = value
}) })
this.notifyChange();
} }
} }
}, },
@ -114,21 +118,34 @@ var app = new Vue({
// methods that implement data logic. // methods that implement data logic.
// note there's no DOM manipulation here at all. // note there's no DOM manipulation here at all.
methods: { methods: {
notifyChange: function () {
todoStorage.save(this.todos)
},
addTodo: function () { addTodo: function () {
var value = this.newTodo && this.newTodo.trim() var value = this.newTodo && this.newTodo.trim()
if (!value) { if (!value) {
return return
} }
this.todos.push({ this.todos.push({
id: 0, // just for the client-side. id: this.todos.length + 1, // just for the client-side.
title: value, title: value,
completed: false completed: false
}) })
this.newTodo = '' this.newTodo = ''
this.notifyChange();
}, },
completeTodo: function (todo) {
if (todo.completed) {
todo.completed = false;
} else {
todo.completed = true;
}
this.notifyChange();
},
removeTodo: function (todo) { removeTodo: function (todo) {
this.todos.splice(this.todos.indexOf(todo), 1) this.todos.splice(this.todos.indexOf(todo), 1)
this.notifyChange();
}, },
editTodo: function (todo) { editTodo: function (todo) {
@ -141,10 +158,11 @@ var app = new Vue({
return return
} }
this.editedTodo = null this.editedTodo = null
todo.title = todo.title.trim() todo.title = todo.title.trim();
if (!todo.title) { if (!todo.title) {
this.removeTodo(todo) this.removeTodo(todo);
} }
this.notifyChange();
}, },
cancelEdit: function (todo) { cancelEdit: function (todo) {
@ -153,7 +171,8 @@ var app = new Vue({
}, },
removeCompleted: function () { removeCompleted: function () {
this.todos = filters.active(this.todos) this.todos = filters.active(this.todos);
this.notifyChange();
} }
}, },