2

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.

2 Answers 2

4

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)
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

2

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.

3 Comments

Hey i want to watch 'Values' property inside criteria->rows->'values'.
I updated my question, i tried using computed. What is the wrong which i am doing?
@Sam your test computed depends upon this.criteria and every row in every criteria and hence will be re-computed on every change. That is how Vue's dependency tracking works. What you can do now is check oldValue and newValue of your watcher and do action only if both are different.

Your Answer

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.