Sam
Sam

Reputation: 2425

Vue- How to watch the properties inside array of objects

I have a JSON like this

'criteria': [
 {
  'row': {
    'name': '1',
    'values': [{}]
  }
 },
 {
  'row': {
    'name': '2',
    'values': [{}]
  }
 }
]

I tried this

watch: {
 criteria: {
   deep: true,
   handler () {
    console.log(this.criteria)
   }
  }
}

But it is watching every change in the criteria. How can i watch only Values? Is there any way to write a custom function and return what ever i want to watch like in angular?

Updated :

I tried this as well

computed: {
test () {
  var values = []
  _.forEach(this.criteria, function (criteria) {
    _.forEach(criteria.row, function (row) {
      values.push(row.values)
    })
  })
  return values
}
},
watch: {
  test () {
   console.log("changed")
  }
}

Still watching every thing.

Upvotes: 2

Views: 6300

Answers (2)

pranavjindal999
pranavjindal999

Reputation: 3047

Simply watch the length of criteria

Like for your use case:

watch: {
 'criteria.length': {
   handler () {
    console.log(this.criteria)
   }
  }
}

Here is the full API:

https://v2.vuejs.org/v2/api/#watch

You can watch anything.

Trick: make a computed prop and watch computed prop.

Upvotes: 2

Phap Duong Dieu
Phap Duong Dieu

Reputation: 165

You need to watch criteria array and detect the changed items in watch handling function.

data: {
    criteria: [
        {
            'row': {
                'name': '1',
                'values': [{}]
            }
        },
        {
            'row': {
                'name': '2',
                'values': [{}]
            }
        }
    ],
    oldCriteria: []
},
methods: {
    setCriteriaValue() {
        // deep clone
        this.oldCriteria = JSON.parse(JSON.stringify(this.criteria))
    },
},
mounted() {

    // TEST: isChange = FALSE
    setTimeout(() => {
        this.criteria[1].row.name = "new name"
    }, 2000);

    // TEST: isChange = TRUE
    setTimeout(() => {
        this.criteria[1].row.values = [10, 20]
    }, 4000);
},
watch: {
    "criteria": {
        deep: true,
        handler: function (after) {
            console.log("criteria watched")

            var vm = this;
            let isChanged = false;

            for (let index = 0; index < after.length; index++) {

                const item = after[index].row
                const props = Object.keys(item)

                isChanged = props.some(function(prop) {
                    if (prop === "values") {
                        const newValue = item[prop]
                        const oldValue = vm.$data.oldCriteria[index].row[prop]

                        return JSON.stringify(newValue) !== JSON.stringify(oldValue);
                    }

                    return false
                })
            }

            if (isChanged) {
                alert("CHANGED!")

                // Do your stuff here
                // ...
            }

            // Update the old value
            vm.setCriteriaValue();
            console.log("isChanged = ", isChanged)
        }
    }
}

Upvotes: 4

Related Questions