0👍
We don’t need to create a modal component for each item in a for-loop.
Because when we create modals in for-loop then all modals’ components have been created separately but they all are binding with the same v-model
, so the last v-model
will always be active and pass only the last item’s data.
This problem can also be fixed by passing the array index or creating a separate v-model using an object but The good practice is to keep the modal component outside of for loop and use it accordingly by passing data of each selected item as a prop.
That means you can do it like this-
(I used dummy data to create the UI)
PARENT COMPONENT-
<template>
<div>
<!-- To open dialog on click on any item -->
<Dialog
v-if="dialog && selectedApp"
v-model="dialog"
:app="selectedApp"
@closeDialog="closeDialog"
/>
<!-- Loop on items -->
<v-col v-for="app in apps" :key="app._id" cols="12">
<v-card class="pa-2 " outlined height="230px">
<v-dialog v-model="dialog">
<template v-slot:activator="{ on: dialog, attrs }">
<v-tooltip right color="#363636" max-width="250px">
<template v-slot:activator="{ on: tooltip }">
<v-img
:src="app.src"
class="white--text align-end"
gradient="to bottom, rgba(0,0,0,.5), rgba(0,0,0,.5)"
height="85%"
v-bind="attrs"
v-on="{ ...tooltip, ...dialog }"
@click="selectedApp = app"
>
<v-card-title v-text="app.title"></v-card-title>
</v-img>
</template>
<span v-if="app.vpnRequired">VPN needed to run!</span>
<v-divider class="my-1" v-if="app.vpnRequired" dark></v-divider>
<span>{{ app.description }}</span>
</v-tooltip>
<!-- shows the link of the clicked app (for example the second of 5) in the array-->
<h1>{{ app.link }}</h1>
</template>
<!-- shows the link of the last ( 5 of 5) app in the array. Why is this link different then the app.link from 2 lines up?-->
<h1>{{ app.link }}</h1>
</v-dialog>
<v-card-actions mb-2>
<v-spacer></v-spacer>
<v-tooltip top color="#363636">
<template v-slot:activator="{ on, attrs }" v-if="app.quickActions">
<v-btn @click="DeleteAppFromQuickActions(app)" icon>
<v-icon v-bind="attrs" v-on="on">
mdi-minus-box-outline
</v-icon>
</v-btn>
</template>
<template v-slot:activator="{ on, attrs }" v-else>
<v-btn @click="AddAppToQuickActions(app)" icon>
<v-icon v-bind="attrs" v-on="on">
mdi-plus-box-outline
</v-icon>
</v-btn>
</template>
<span v-if="app.quickActions">Delete from QuickActions</span>
<span v-else>Add to QuickActions</span>
</v-tooltip>
<v-spacer></v-spacer>
</v-card-actions>
</v-card>
</v-col>
</div>
</template>
<script>
import Dialog from "/var/www/html/weresearchfrontend/src/Dialog.vue";
export default {
name: "ParentComponent",
data() {
return {
dialog: false,
selectedApp: null,
apps: [
{
title: "A",
vpnRequired: true,
src: "https://source.unsplash.com/user/c_v_r/1900x800",
description: "Hello Google",
link: "https://google.com",
quickActions: true,
},
{
title: "B",
vpnRequired: true,
src: "https://source.unsplash.com/user/c_v_r/100x100",
description: "Hello Github",
link: "https://github.com",
quickActions: true,
},
],
};
},
components: {
Dialog,
},
methods: {
closeDialog: function() {
this.dialog = false;
// reset selected app also
this.selectedApp = app;
},
},
};
</script>
CHILD COMPONENT (DIALOG COMPONENT)-
<template>
<v-dialog :value="value">
<v-card>
<v-container fluid>
<v-row>
<v-col fixed style="background:#363636;" class="d-flex" cols="12">
<span class="white--text font-weight-bold"
>{{ app.title }} > {{ app.description }} > {{ app.link }}</span
>
<v-spacer></v-spacer>
<v-btn plain color="grey" :href="app.link" target="_blank">
<v-icon>mdi-open-in-new</v-icon>
</v-btn>
<v-btn @click="$emit('closeDialog')" plain color="grey">
<v-icon>mdi-close-box-outline</v-icon>
</v-btn>
</v-col>
<v-col cols="12">
<iframe :src="app.link" width="100%" height="800px" frameborder="0">
</iframe>
</v-col>
</v-row>
</v-container>
</v-card>
</v-dialog>
</template>
<script>
export default {
name: "Dialog",
props: ["value", "app"],
};
</script>
Source:stackexchange.com