Home > Enterprise >  Passing props dynamically to a component inside a v-for loop
Passing props dynamically to a component inside a v-for loop

Time:11-23

I have a v-for loop that iterates through an array of meetings (meetings between sellers and potential buyers of used cars) and prints a card for each meeting, a basic display of who the meeting is with, what car it is about and the scheduled date. Now, I implemented a button that when clicked, opens a dialog with a Google Maps component that shows the marker for the agreed location of the meeting.

My problem is that no matter what card I click on, the dialog will always display the location of the LAST card, regardless of which has been clicked. I would think that since Im calling the component INSIDE the v-for loop it would pass props dynamically for each card, on each iteration, but that does not seem to be the case.

Here is the HTML:

<div
      v-for="meeting in meetings"
      :key="meeting.did"
      
    >
      <q-card >
        <q-dialog  v-model="mapDialog">
          <MeetMapComponent
            :key="componentKey"
            :mapDiv="mapDiv"
            :mapData="meeting.address"
            :buyerName="meeting.name"
          />
        </q-dialog>
        <q-card-section
          
          :style="`background-image: url(${meeting.car.carImg})`"
        >
          <router-link
            :to="`/user/meet/edit/${meeting.did}`"
            style="text-decoration: none"
          >
            <q-icon
              @click="fetchMeeting(meeting.did)"
              name="fa-solid fa-pencil editNameIcon q-mb-sm q-ml-sm"
            ></q-icon>
          </router-link>
          <q-icon
            name="fa-solid fa-trash editNameIcon q-mb-sm q-ml-sm"
            @click="triggerDelete(meeting.did)"
          ></q-icon>
        </q-card-section>

        <q-card-section>
          <div >
            <span>Encuentro Con</span> {{ truncateString(meeting.name, 30) }}
          </div>
          <div >
            <span>Agendado para el </span>
            <p>{{ truncateString(meeting.date, 120) }}</p>
          </div>
          <div >
            <q-btn
              @click="mapDialog = true"
              
              :
              >Ver Ubicación</q-btn
            >
          </div>
        </q-card-section>
      </q-card>
    </div>

And here is the code for the MeetMapComponent:

<template>
  <div >
    <div ref="mapDiv" style="width: 100%; height: 500px" />
    <h5 >{{ props.mapData.address }}</h5>
  </div>
</template>

<script setup>
import { ref } from "vue";
import { useAuthStore } from "stores/auth";
import { storeToRefs } from "pinia";
import { Loader } from "@googlemaps/js-api-loader";

const props = defineProps({
  mapData: Object,
  buyerName: String,
});

const GOOGLE_MAPS_API_KEY = "...";
const loader = new Loader({ apiKey: GOOGLE_MAPS_API_KEY });
const mapDiv = ref(null);
async function mapRender() {
  await loader.load();
  const map = new google.maps.Map(mapDiv.value, {
    mapTypeId: "roadmap",
    center: props.mapData.coordinates,
    zoom: 13,
  });
  console.log(map);
  new google.maps.Marker({
    position: props.mapData.coordinates,
    map,
    title: `Encuentro con ${props.buyerName}`,
  });
}

mapRender();
</script>

CodePudding user response:

I will help you as much as I understand. You use the mapDialog variable to open the dialogue. But even if this variable is used in v-for, its reference does not change. For this reason, when you want to open a modal, all modals may be opened and the last one may appear because it is the last one opened. Please check the dom.

I think this method can solve the problem.

in script

const meetings  = [
  {
    did: 'some value',
    address: 'some address',
    name: 'some name',
    // add modal flag
    showMapModal: false
  }
]

template

<div
      v-for="meeting in meetings"
      :key="meeting.did"
      
    >
      <q-card >
        <q-dialog  v-model="meeting.showMapModal">
          <MeetMapComponent
            :key="componentKey"
            :mapDiv="mapDiv"
            :mapData="meeting.address"
            :buyerName="meeting.name"
          />
        </q-dialog>
        </q-card>
        </div>
  • Related