I've been practicing Vue.js recently. Right now, I am making a simple todo list. Some buttons does't work which filter tasks. All button for listing every single tasks. ongoing button is for uncheck input checkbox square. done button is for checked ones.
Does anybody know how to fix?
new Vue({
el: '#app',
data: {
inputTask:'',
todos: [
{task:'task01', done: false},
{task:'task02', done: false},
{task:'task03', done: true},
{task:'task04', done: true},
{task:'task05', done: false},
]
},
computed: {
},
methods: {
allTask : function () {
this.todos
},
ongoingTask: function () {
this.todos = this.todos.filter(function (el) {
el.value = false
})
},
doneTask: function () {
this.todos = this.todos.filter(function (el) {
el.checked
})
},
addTask: function() {
const todo = { task: this.inputTask, done:false, };
this.todos.push(todo);
this.inputTask ='';
},
deleteTask: function (index) {
this.todos.splice(index, 1);
}
}
})
.done {text-decoration: line-through;}
<div id="app">
<input type="text" v-model="inputTask">
<button @click="addTask">Add</button>
<div>
<button @click="allTask">All</button>
<button @click="ongoingTask">Ongoing</button>
<button @click="doneTask">Done</button>
</div>
<ul>
<li v-for="(todo, index) in todos" :key="todo">
<input type="checkbox" v-model="todo.done">
<span :class="{done:todo.done}">{{todo.task}}</span>
<button @click="deleteTask(index)">Remove</button>
</li>
</ul>
<p v-show="todos.length===0">Nothing to do</p>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
2 Answers 2
You should use computed property to filter your task. And i guess you can add some improvements for user friendly interface. So your code will look like this:
new Vue({
el: '#app',
data: {
type: '',
inputTask:'',
todos: [
{task:'task01', done: false},
{task:'task02', done: false},
{task:'task03', done: true},
{task:'task04', done: true},
{task:'task05', done: false},
]
},
methods: {
setFilterType(type) {
this.type = type;
},
addTask() {
const todo = { task: this.inputTask, done: false};
this.todos.push(todo);
this.inputTask = '';
},
deleteTask(index) {
this.todos.splice(index, 1);
}
},
computed: {
filteredTodos() {
return this.todos.filter(todo => {
switch(this.type) {
case 'ongoing':
return !todo.done;
case 'done':
return todo.done;
default:
return true;
}
});
}
}
})
And template:
<div id="app">
<input type="text" v-model="inputTask">
<button @click="addTask">Add</button>
<div>
<button :class="{active: type ===''}" @click="setFilterType('')">All</button>
<button :class="{active: type ==='ongoing'}" @click="setFilterType('ongoing')">Ongoing</button>
<button :class="{active: type ==='done'}" @click="setFilterType('done')">Done</button>
</div>
<ul>
<li v-for="(todo, index) in filteredTodos" :key="todo">
<input type="checkbox" v-model="todo.done">
<span :class="{done:todo.done}">{{todo.task}}</span>
<button @click="deleteTask(index)">Remove</button>
</li>
</ul>
<p v-show="todos.length===0">Nothing to do</p>
</div>
Also i've added active
class to button. So you can highlight via css current sorting.
More about computed you can read here
3 Comments
:class="{active: type ==='ongoing'}"
dosen't add ongoing
class according to chrome devtool even though :class="{active: type ==='done'}"
is fine. You know why by any chance?active
class to the button, which was pressed last. It's adding keys of the object, that you are passing to :class
.All your filter function on ongoingTask
and doneTask
are wrong, they should return a value; take a look at how filter function works: here.
I'm not sure what's the intended behavior of ongoingTaks is, but I guess the following should solve the problem. Please let me know and I'll update the answer correspondingly.
// ...
ongoingTask: function () {
this.todos = this.todos.filter(function (el) {
return el.value === false
})
},
doneTask: function () {
this.todos = this.todos.filter(function (el) {
return el.checked
})
},
// ...
EDIT:
The other part of the issue had to do with the logic, as soon as you clicked on any button that triggers the filtering, data in the state is removed (for instance, if I'm in the default view, viewing all todos, when I click in the Ongoing button, all the done TODO in the list gets removed and forever lost!); ideally you should keep that data and use computed properties to tackle the issue, here you have a working example (I'm using a Vue component here just for the sake of condensing all data in one place):
<template>
<div id="app">
<input type="text" v-model="inputTask">
<button @click="addTask">Add</button>
<div>
<button @click="changeFilter('all')">All</button>
<button @click="changeFilter('ongoing')">Ongoing</button>
<button @click="changeFilter('done')">Done</button>
</div>
<ul>
<li v-for="(todo, index) in getTasksList()" :key="{index}">
<input type="checkbox" v-model="todo.done">
<span :class="{done:todo.done}">{{todo.task}}</span>
<button @click="deleteTask(index)">Remove</button>
</li>
</ul>
<p v-show="todos.length===0">Nothing to do</p>
</div>
</template>
<script>
export default {
name: "App",
data: () => ({
inputTask: "",
currentFilter: "ongoing",
todos: [
{ task: "task01", done: false },
{ task: "task02", done: false },
{ task: "task03", done: true },
{ task: "task04", done: true },
{ task: "task05", done: false }
]
}),
computed: {
ongoingTasks: function() {
return this.todos.filter(function(todo) {
return todo.done === false;
});
},
doneTasks: function() {
return this.todos.filter(function(el) {
return el.done;
});
}
},
methods: {
changeFilter(newFilter) {
this.currentFilter = newFilter;
},
addTask: function() {
const todo = { task: this.inputTask, done: false };
this.todos.push(todo);
this.inputTask = "";
},
deleteTask: function(index) {
this.todos.splice(index, 1);
},
getTasksList() {
switch (this.currentFilter) {
case "ongoing":
return this.ongoingTasks;
case "done":
return this.doneTasks;
case "all":
default:
return this.todos;
}
}
}
};
</script>
I hope this helps!
2 Comments
ongoingTask
should update a list for the done: false
items which is task01
,task02
,task05
. doneTask
should update a list for the done: true
items which is task03
,task04
allTask
shoule lineup eveything and is not working either :'(Vue component
stuff, it's over my head :'( Since, I have not learned yet. However, I will get your point and answer as soon as I can. I'll provide solved state to other buy because gave the answer earlier. Sorry about it. Thank you very much for your help anyways!!!
this.todos = this.todos.filter(function (el) {
<= you are replacing your original list that had everything, with a subset. After which point, you will have lost some of the original elements. You need to either store the filter results in a secondary element, or make the method return the filtered results.