I am attempting to pass user id's fetched from an API trough props from parent (App) to child (Modal). The problem is that when I pass the props down to the modal they don't render as they should in the div with the modal-body class, in fact all of them display an id of 1.
App.vue:
<template>
<div >
<table >
<thead>
<tr>
<th scope="col">ID</th>
<th scope="col">Name</th>
<th scope="col">Username</th>
</tr>
</thead>
<tbody v-for="user in users" :key="user.id">
<tr>
<th scope="row">{{ user.id }}</th>
<td>{{ user.name }}</td>
<td>{{ user.username }}</td>
<td>
<Modal :id="user.id" />
</td>
</tr>
</tbody>
</table>
</div>
<pre>{{ user }}</pre>
</template>
<script>
import axios from "axios";
import Modal from "@/components/Modal.vue";
export default {
name: "App",
components: {
Modal,
},
data() {
return {
users: null,
};
},
methods: {
async load_users() {
try {
const { data } = await axios.get(
"https://jsonplaceholder.typicode.com/users"
);
this.users = data;
} catch (error) {
console.log("error");
}
},
},
mounted() {
this.load_users();
},
};
</script>
Modal.vue:
<template>
<!-- Button trigger modal -->
<button
type="button"
data-bs-toggle="modal"
data-bs-target="#exampleModal"
>
Delete
</button>
<!-- Modal -->
<div
id="exampleModal"
tabindex="-1"
aria-labelledby="exampleModalLabel"
aria-hidden="true"
>
<div >
<div >
<div >
<h5 id="exampleModalLabel">Modal title</h5>
<button
type="button"
data-bs-dismiss="modal"
aria-label="Close"
></button>
</div>
<div >
Are you sure you want to delete user: {{ id }}
</div>
<div >
<button
type="button"
data-bs-dismiss="modal"
>
Close
</button>
<button type="button" >Save changes</button>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Modal",
props: ["id"],
};
</script>
The page preview is the following:
It does not matter on which Delete button I click the id is always 1.
But when I inspect the props in the Vue Devtools they are different, for the second for example it appears 2 as it should:
Any help is appreciated.
Thank you.
CodePudding user response:
You are rendering 10 modals each with the same id - exampleModal
, so it's always the first one which is opened. This is why you are experiencing the behaviour you describe.
However - the real problem is with your structure.
Why are you rendering 10 modals? Why not render one and pass in the respective props?
Something like this:
<template>
<Modal :id="modal.userId" v-if=""modal.isActive />
<tbody v-for="user in users" :key="user.id">
<tr>
<th scope="row">{{ user.id }}</th>
<td>{{ user.name }}</td>
<td>{{ user.username }}</td>
<td>
<button type="button"
@click="onClick(user.id)"
>
Delete
</button>
</td>
</tr>
</tbody>
</template>
<script>
export default {
name: "App",
components: {
Modal,
},
data() {
return {
users: null,
modal: {
isActive: false,
userId: null,
}
};
},
methods: {
onClick(userId) {
Object.assign(this.modal, { isActive: true, userId });
}
}
}
</script>
CodePudding user response:
The issue is inside of the css framework you are using. Inside your modals, you have each of them having the same ID to open the Modal. So, when you click any of the buttons, they open the first modal in the dom. I would switch any instance of data-bs-target="#exampleModal"
to :data-bs-target="`#exampleModal-${id}`"
Alternatively, a possible better way would be to refactor some of the code and make all of the modals lazily loaded. Though, this would take some work.