Hilmanrdn Hilmanrdn - 1 year ago 61
Javascript Question

Vue todolist toggle class only on one lists

im trying to create a todolist with vuejs, adding and removing list is working. I'm struggling now with the -done function- which will toggle a class to append a line-through to a list.

The problem is everytime i toggle the -done button- the style will apply to all lists not only one list, here is my code

.completed{
text-decoration:line-through;
}


<div id="app">
<input type="text" v-model="newTodo" v-on:keyup.enter="addTodo">
<ul>
<li v-if="!todos.length">no items</li>

<li v-for="todo in todos">
<span v-bind:class="{'completed':done}"> {{ todo }}</span>
<button v-on:click="removeTodo($index)">X</button>
<button v-on:click="toggleC">done</button>
</li>
</ul>
</div>

<script src="http://cdnjs.cloudflare.com/ajax/libs/vue/1.0.25/vue.min.js"></script>
<script>

new Vue({
el: '#app',
data: {
newTodo : '',
todos : [],
done : false
},
methods: {
addTodo: function(){
var text = this.newTodo.trim()
if (text){
this.todos.push(text);
this.newTodo = '';
}
},
removeTodo: function (index){
this.todos.splice(index, 1)
},
toggleC: function(){
this.done = !this.done
}
}
})

</script>
</body>
</html>


thanks!

Answer Source

Currently, you only have one done variable, and it's associated with the Vue instance. Thus either everything is done, or not done. Instead, give each todo it's own done property.

When you add a todo, set done to false, and set a text property to the text value:

addTodo: function(){
  var text = this.newTodo.trim()
  if (text){
    this.todos.push({text: text, done: false});
    this.newTodo = '';
  }
},

Modify the HTML to pass the current todo in the v-for loop:

<li v-for="todo in todos">
  <!-- We conditionally add the 'completed' class based on todo.done -->
  <span v-bind:class="todo.done ? 'completed' : ''"> {{ todo.text }}</span>
  <button v-on:click="removeTodo($index)">X</button>

  <!-- Notice we can pass the current todo to toggleC -->
  <button v-on:click="toggleC(todo)">done</button>
</li>

Then, in the toggleC method, simply toggle the done status of the current todo:

toggleC: function(todo){
  todo.done = !todo.done
}

Here it is all put together!

new Vue({
  el: '#app',
  data: {
    newTodo : '',
    todos   : [],
  },
  methods: {
    addTodo: function(){
      var text = this.newTodo.trim()
      if (text){
        this.todos.push({text: text, done: false});
        this.newTodo = '';
      }
    },
    removeTodo: function (index){
      this.todos.splice(index, 1)
    },
    toggleC: function(todo){
      todo.done = !todo.done
    }
  }
})
.completed{
  text-decoration:line-through;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.25/vue.js"></script>
<div id="app">
  <input type="text" v-model="newTodo" v-on:keyup.enter="addTodo">
  <ul>
    <li v-if="!todos.length">no items</li>

    <li v-for="todo in todos">
      <!-- We conditionally add the 'completed' class based on todo.done -->
      <span v-bind:class="todo.done ? 'completed' : ''"> {{ todo.text }}</span>
      <button v-on:click="removeTodo($index)">X</button>
      
      <!-- Notice we can pass the current todo to toggleC -->
      <button v-on:click="toggleC(todo)">done</button>
    </li>
  </ul>
</div>