1๐
OK. Adding the event listener @update:user
and handling the update manually (using a custom method) solves the issue.
But if I bind directly to the properties of the user object, as bellow, then the users
array (in the parent) gets updated properly, even though Iโm using the filteredUsers
property.
<template>
<div>
<User
v-for="(user, index) in filteredUsers"
:key="index"
v-model:first-name="filteredUsers[index].firstName"
v-model:last-name="filteredUsers[index].lastName"
></User>
</div>
</template>
<script>
import User from '../components/User.vue'
export default {
components: {
User
},
data() {
return {
users: [
{
firstName: 'jean',
lastName: 'paul',
},
{
firstName: 'pierre',
lastName: 'smith',
},
{
firstName: 'jean',
lastName: 'valjean',
}
],
}
},
computed: {
filteredUsers() {
return this.users.filter(user => user.firstName.includes('jean'))
}
},
watch:{
users: {
handler(newVal, oldVal) {
console.log('users changed')
},
deep: true
}
}
}
</script>
// Child User.vue
<script>
export default {
props: {
firstName: String,
lastName: String,
},
emits: [
'update:firstName',
'update:lastName',
],
}
</script>
<template>
<div>
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)"
/>
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)"
/>
</div>
</template>
Why does it work in such case and not when passing the object as a prop (v-model:user="filteredUsers[index]"
) ? (as in my first question)
- [Vuejs]-Convert anonymous user with Firebase: Cannot read property 'getAuthResponse' of undefined
- [Vuejs]-Ionic Vue IonDatetimeButton inside Modal bugs
0๐
You are processing all the data based on a computed property which is producing the results based on users array as a "new object". You have to find the array index and then update it. Review my code below:
I have only changed the Parent component, integrated the event listener and a function that processes it. Happy Coding!
// Parent component
<template>
<div>
<User v-for="(user, index) in filteredUsers" @update:user="updateUser" :key="index"
v-model:user="filteredUsers[index]"></User>
</div>
</template>
<script>
import _ from 'lodash'
import User from './components/User.vue'
export default {
components: {
User
},
data() {
return {
users: [
{
id: 1, //we are using it to identify user data
firstName: 'jean',
lastName: 'paul',
},
{
id: 2,
firstName: 'pierre',
lastName: 'smith',
},
{
id: 3,
firstName: 'jean',
lastName: 'valjean',
}
],
}
},
computed: {
filteredUsers() {
// Problem: When filtering the users, users is no longer getting updated when editing the user in the child component.
return this.users.filter(user => user.firstName.includes('jean'))
// If not filtering, then users is well updated and the watcher notice the change.
// return this.users
}
},
methods: {
updateUser(user) {
let uIdx = _.findIndex(this.users, function (u) { return u.id == user.id; });
console.log('user', user, uIdx);
if (this.users[uIdx]) {
this.users[uIdx] = user;
}
}
},
watch: {
users: {
handler(newVal, oldVal) {
console.log('users changed')
},
deep: true
}
}
}
</script>
Another method which can work without "$emit"
//Parent Component
<template>
<div>
{{ users }}
<hr>{{ filteredUsers }}
<User v-for="(user, index) in filteredUsers" :key="index" v-model:user="filteredUsers[index]"></User>
</div>
</template>
<script>
import User from './components/User.vue'
export default {
components: {
User
},
data() {
return {
users: [
{
firstName: 'jean',
lastName: 'paul',
},
{
firstName: 'pierre',
lastName: 'smith',
},
{
firstName: 'jean',
lastName: 'valjean',
}
],
}
},
computed: {
filteredUsers() {
return this.users.filter(user => user.firstName.includes('jean'))
}
},
watch: {
users: {
handler(newVal, oldVal) {
console.log('users changed')
},
deep: true
}
}
}
</script>
We are not using emit in child component
// Child User.vue
<script>
export default {
props: {
user: Object
}
}
</script>
<template>
<div>
<input type="text" v-model="user.firstName" />
<input type="text" v-model="user.lastName" />
</div>
</template>