On top of How to watch only after the initial load from API in VueJS?, I wanted to detect any changes in values of the properties in the json object.
Initially the user object is
user: {
userId: 0,
id: 0,
title: "",
completed: false,
},
I have two input fields,
<input type="text" v-model="user.userId" /> <br />
<input type="text" v-model="user.title" /> <br />
and a button <button :disabled="isLoaded">Update</button>
If none of the input values changed, the button should be still disabled. Example, if the userId is changed to 1, the button should be enabled but if the value is changed back to 0, the button should be disabled. I referred Vue js compare 2 object and remove differences in watcher and I tried following but failed.
<template>
<div id="app">
<div v-if="!isFetching">
<input type="text" v-model="user.userId" /> <br />
<br />
<input type="text" v-model="user.title" /> <br />
<br />
<button :disabled="isLoaded">Update</button>
</div>
<div v-else>Loading...</div>
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
user: {
userId: 0,
id: 0,
title: "",
completed: false,
},
isFetching: false,
isLoaded: true,
};
},
watch: {
user: {
handler(oldVal, newVal) {
this.checkObject(oldVal, newVal);
},
deep: true,
},
},
methods: {
checkObject: (obj1, obj2) => {
const isEqual = (...objects) =>
objects.every(
(obj) => JSON.stringify(obj) === JSON.stringify(objects[0])
);
console.log(obj1, obj2);
console.log(isEqual(obj1, obj2));
},
},
created() {
this.isFetching = true;
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => {
this.user = json;
this.isLoaded = true;
})
.finally(() => (this.isFetching = false));
},
};
</script>
Here's a live demo: https://codesandbox.io/embed/friendly-hopper-ynhxc?fontsize=14&hidenavigation=1&theme=dark
CodePudding user response:
Here is one way you could solve this. So below I'm storing two user objects, one is my base line comparison compareUser
, and the other is the user
that is under edit. When something changes which the deep watch on user
will notify me about, I use a utility function like isEqual
from lodash to perform a semantic comparison of the base line object and the current user object, and see if there are any differences.
If I want to update my base line that I'm comparing to, then I update the compareUser
from the current user
by cloning it.
You can of course replace things like isEqual
and cloneDeep
by rolling your own to avoid the extra library if that's an issue.
<script>
import { isEqual, cloneDeep } from "lodash";
const createDefault = function () {
return {
userId: 0,
id: 0,
title: "",
completed: false,
};
};
export default {
name: "App",
data() {
return {
compareUser: createDefault(),
user: createDefault(),
isLoaded: false,
isDifferent: false,
};
},
watch: {
user: {
handler() {
this.isDifferent = !isEqual(this.user, this.compareUser);
},
deep: true,
},
},
methods: {
setCompareUser(user) {
this.compareUser = cloneDeep(user);
this.isDifferent = false;
},
},
async created() {
const response = await fetch(
"https://jsonplaceholder.typicode.com/todos/1"
);
const user = await response.json();
this.user = user;
this.setCompareUser(user);
this.isLoaded = true;
},
};
</script>