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: "",
pleted: 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 pare 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: "",
pleted: 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(";)
.then((response) => response.json())
.then((json) => {
this.user = json;
this.isLoaded = true;
})
.finally(() => (this.isFetching = false));
},
};
</script>
Here's a live demo: ;hidenavigation=1&theme=dark
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: "",
pleted: 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 pare 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: "",
pleted: 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./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
Share Improve this question asked Nov 8, 2021 at 21:03 user16583522user16583522 4-
1
You could create a puted value with the given logic to evaluate whether disabled shall be true or false.
puted: { disabled() { return //elaborated function which checks all necessary information }}
and then bind it on the item:disabled="disabled"
– D.Schaller Commented Nov 8, 2021 at 21:09 - 1 FWIW, the problem with the answer you picked is that it adds plexity but doesn't solve problems with a watcher. You still use isLoaded property that serves no good purpose. – Estus Flask Commented Nov 8, 2021 at 21:09
- @EstusFlask can you suggest a way? I am too confused – user16583522 Commented Nov 9, 2021 at 23:01
-
Loading state can be handled like I showed in previous answer, there's no need for a watcher for it. You preferably shouldn't enable a form before data is loaded, if a user starts to fill the form and then it's changed when initial data arrives, this results in bad UX. As for form changes, it's like current answer shows. You need to copy
user
and pare against it. – Estus Flask Commented Nov 10, 2021 at 8:18
1 Answer
Reset to default 4Here is one way you could solve this. So below I'm storing two user objects, one is my base line parison pareUser
, 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 parison 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 paring to, then I update the pareUser
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: "",
pleted: false,
};
};
export default {
name: "App",
data() {
return {
pareUser: createDefault(),
user: createDefault(),
isLoaded: false,
isDifferent: false,
};
},
watch: {
user: {
handler() {
this.isDifferent = !isEqual(this.user, this.pareUser);
},
deep: true,
},
},
methods: {
setCompareUser(user) {
this.pareUser = cloneDeep(user);
this.isDifferent = false;
},
},
async created() {
const response = await fetch(
"https://jsonplaceholder.typicode./todos/1"
);
const user = await response.json();
this.user = user;
this.setCompareUser(user);
this.isLoaded = true;
},
};
</script>
Demo: https://codesandbox.io/s/modern-tdd-yg6c1