Mr Bell
Mr Bell

Reputation: 9368

How to $watch property of a list item in VueJS

How can I $watch changes to specific properties of a list item? For instance in the below code, I want to know whenever the Done property on any of the TODO list items changes.

I see from the docs that I can watch subproperties of objects, like myObjects.done in the code below, but I am not sure about the syntax for lists.

I should also mention I would prefer to $watch the data instead of putting event handlers in the UI, and function calls in any spot that changes the property

var vm = new Vue({
  el: "#app",
  data: {
    myObject: { done: true },
    todos: [
      { text: "Learn JavaScript", done: false },
      { text: "Learn Vue", done: false },
      { text: "Play around in JSFiddle", done: true },
      { text: "Build something awesome", done: true }
    ]
  },
});

//This works wonderfully on non list items
vm.$watch("myObject.done", function(val)
{
    console.log("myObject.done changed", val);
});

//How do I monitor changes to the done property of any of the todo items?
vm.$watch("todos[*].done", function(val)
{
    console.log("todos.done changed", val);
})

JSFiddle here: http://jsfiddle.net/eywraw8t/376544/

Upvotes: 4

Views: 4924

Answers (3)

Niaz Estefaie
Niaz Estefaie

Reputation: 577

I used this and it works for me.

var vm = new Vue({
  el: "#app",
  data: {
    myObject: { done: true },
    todos: [
      { text: "Learn JavaScript", done: false },
      { text: "Learn Vue", done: false },
      { text: "Play around in JSFiddle", done: true },
      { text: "Build something awesome", done: true }
    ]
  },
  watch:{
  todo: function(val) {
  console.log ("This TODO is Done", val)
  }
});
<template>
  <div class="mainDiv" v-for="(index, todo) from todos">
    <div>{{todo.text}}</div>
    <input type="checkbox" v-model="todo[index].done">
  </div>
</template>

Upvotes: 0

Yiin
Yiin

Reputation: 659

To watch specific property, I'd create another component for the list item and pass the item as value to watch the changes from that component.

Vue.component("TaskItem", {
    template: `
        <li
            class="task-item"
            :class="{ done: complete }"
        >
            <p>{{ task.description }}</p>
            <input type="checkbox" v-model="complete">
        </li>
    `,
    props: ["task"],
    computed: {
        complete: {
            set(done) {
                this.$emit("complete", this.task, done);
                // we force update to keep checkbox state synced
                // in case if task.done was not toggled by parent component
                this.$forceUpdate();
            },
            get() {
                return this.task.done;
            }
        }
    }
});

new Vue({
    el: "#app",
    template: `
        <div>
            <ul class="task-list">
                <TaskItem
                    v-for="(task, i) in tasks"
                    :key="i"
                    :task="task"
                    @complete="complete"
                />
            </ul>
            <button @click="completeFirstTask">Complete first task</button>
        </div>
    `,
    data() {
        return {
            tasks: [
                { description: "Get milk", done: false },
                { description: "Barber shop", done: true },
                { description: "Fix sleep cycle", done: false }
            ]
        };
    },
    methods: {
        complete(item, done) {
            item.done = done;
        },
        completeFirstTask() {
            this.tasks[0].done = true;
        }
    }
});

https://codesandbox.io/s/wqrp13vp25

Upvotes: 1

Andrius Rimkus
Andrius Rimkus

Reputation: 653

With your current approach, you'd have to deep-watch the array and do some heavy computations in order to figure out the changed element. Check this link for the example: Vue - Deep watching an array of objects and calculating the change?

I think the better approach would be using change event handler:

<input type="checkbox" v-model="todo.done" @change="onTodoChange(todo, $event)">

JSFiddle: http://jsfiddle.net/47s0obuc/

Upvotes: 4

Related Questions