1

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>

asked May 26, 2020 at 16:56
2
  • 1
    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. Commented May 26, 2020 at 17:00
  • 1
    all your filter functions are wrong. None return a value, and the first one is trying to set a value in the filter function. Commented May 26, 2020 at 17:01

2 Answers 2

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

answered May 26, 2020 at 17:23
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you answering me. Grrrr, Vuejs is pretty complicated. understanding your answer little by little. But it seems like :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?
@user10991526 it's adding active class to the button, which was pressed last. It's adding keys of the object, that you are passing to :class.
Aww, ok. got it. misunderstanding. I need to practice anyways. Thank you very much for your help.
1

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!

answered May 26, 2020 at 17:09

2 Comments

Thank you for your comment. Acttually, I tried your way before... Ideal behaviour shoube be: 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 :'(
Thank you for your help I got the logic. Thank you. But about 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!!!

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.