<html>
<head>
<title>
Vue 3 Todo App
</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div class="container" id="todoapp">
<div class="row">
<div class="section">
<h4>Add Todos</h4>
</div>
<div class="divider"></div>
<div class="section">
<form class="col s12">
<div class="row">
<div class="input-field col s4">
<i class="material-icons prefix">title</i>
<textarea v-model="todo.title" id="todo_title" class="materialize-textarea"></textarea>
<label for="todo_title">Title</label>
</div>
<div class="input-field col s4">
<i class="material-icons prefix">description</i>
<textarea v-model="todo.description" id="todo_description" class="materialize-textarea"></textarea>
<label for="todo_description">Description</label>
</div>
<div class="s4">
<a class="btn-floating btn-large waves-effect waves-light red tooltipped" data-position="bottom" data-tooltip="Add Todo!" @click="addTodo()"><i class="material-icons">add</i></a>
</div>
</div>
</form>
</div>
</div>
<div class="row">
<div class="divider"></div>
<div class="section">
<h5>Your Todos</h5>
</div>
<div class="divider"></div>
<div class="section">
<table class="striped centered responsive-table">
<thead>
<th>
</th>
<th>
Title
</th>
<th>
Description
</th>
<th>
</th>
</thead>
<tbody>
<tr v-for="(todo,id) in todos">
<td>
{{id}}
</td>
<td>
{{todo.title}}
</td>
<td>
{{todo.description}}
</td>
<td>
<a v-show="!todo.done" class="btn-floating btn-large waves-effect waves-light light-green accent-4 tooltipped" data-position="bottom" data-tooltip="I'm done with this one!" @click="markAsDone(todo.id)"><i class="material-icons">check</i></a>
<i v-if="todo.done" class="todo-done-tick material-icons tooltipped" data-position="bottom" data-tooltip="You're done with this one!">check</i>
</td>
</tr>
<tr v-show="todoCount == 0">
<td colspan="4">You haven't added any Todos yet :(</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
const TodoApp = {
data() {
return {
todoCount: 0,
todo: {
id: 0,
title: "",
description: "",
done: false
},
todos: {}
};
},
mounted() {
const vm = this;
vm.initialize();
},
methods: {
initialize() {
const vm = this;
vm.addTooltips(vm.findTooltippedElementsFromDOM());
},
addTooltips(tooltippedElements) {
const vm = this;
M.Tooltip.init(tooltippedElements, {});
},
findTooltippedElementsFromDOM() {
const vm = this;
return document.querySelectorAll(".tooltipped");
},
addTodo() {
const vm = this;
if (!vm.todo.title || vm.todo.title.trim() === "") {
M.toast({ html: "Need a title for this Todo!", classes: "rounded" });
return;
}
if (!vm.todo.description || vm.todo.description.trim() === "") {
M.toast({
html: "A small description would be nice!",
classes: "rounded"
});
return;
}
vm.todo.id = ++vm.todoCount;
vm.todos[vm.todo.id] = vm.todo;
vm.todo = { title: "", description: "" };
vm.addTooltipsToDynamicElements();
},
markAsDone(id) {
const vm = this;
vm.todos[id].done = true;
vm.addTooltipsToDynamicElements();
},
addTooltipsToDynamicElements() {
const vm = this;
setTimeout(function () {
vm.addTooltips(vm.findTooltippedElementsFromDOM());
}, 500);
}
}
};
Vue.createApp(TodoApp).mount("#todoapp");