Search code examples
modal-dialogvuejs3v-for

Not able to push return of function into vue3 modal


I have a function that is filtering data based upon clickable button (seen in console logs). When I put this array into my modal as a v-for 'loop', I break my button function. Why? Each time I do this, I get 'undefined' results. This idea worked fine for displaying table row data based on the skedDatas array.

Function getrowid within /src/pages/courses/ammo04.vue. Code is at github: https://github.com/EnergeticPixels/catalog


Solution

  • I would not call methods directly in the template of your component. Any time a rerender happens, the method reruns, which is going to cause problems and other side effects if you're not very careful. I suggest using a ref variable to hold the data. Being scoped to the entire component, you can use it in both your script and template code without needing to pass it around/return it anywhere.

    First, updating the button to pass classId as a parameter to the toggleModal function, showing that the use of data attributes is not needed with Vue:

    <td><button @click.prevent="toggleModal(skedData.classId)">{{ skedData.contact }}</button></td>
    
    const toggleModal = (classId) => {
      getclickedrow(classId);
      modalActive.value = !modalActive.value;
    }
    

    Passing it again as a parameter to getclickedrow and using a ref to hold the result of the array filter (which I would change to Array.find if the expected result is always 1 object, which I think it is...):

    const skedfiltered = ref(null);
    const getclickedrow = (classId) => {
      skedfiltered.value = skedDatas.find(offering => {
        return offering.classId === classId
      });
    };
    

    I saw this next code was commented out, but I noticed if made into a computed property it will automatically re-evaluate itself based on the above skedfiltered ref, always giving you the desired Poc. This also looks like a better job for Array.find than Array.filter. Just be careful when skedfiltered is initially null, finding or filtering won't work (hence the optional chaining to catch this)

    // filter sitePoc array for matching clicked contactId
    const filteredPoc = computed(() => sitePocs.find(poc => {
      return poc.contactId === skedfiltered.value?.contactId
    }))
    

    computed needs to be imported, so change the line at the top:

    import { ref, computed } from 'vue';
    

    Finally, setting the rest of the template code to display all of the data evaluated above:

    <ContactInfo v-if="filteredPoc" :filteredPoc="filteredPoc" class='contactInfo' @close="toggleModal" :modalActive="modalActive">
      <h2 class="title has-text-centered is-size-3">{{ filteredPoc.pocTitle }}</h2>
      <p class="">Please contact the following individual(s):</p>
      <ul>
        <li><span class="has-text-weight-bold">Name:</span> {{ filteredPoc.pocName }}</li>
        <li><span class="has-text-weight-bold">Email:</span> {{ filteredPoc.pocEmail }}</li>
        <li><span class="has-text-weight-bold">Commercial Phone 1:</span> {{ filteredPoc.pocPhone1 }}</li>
        <li><span class="has-text-weight-bold">Commercial Phone 2:</span> {{ filteredPoc.pocPhone2 }}</li>
        <li><span class="has-text-weight-bold">DSN:</span> {{ filteredPoc.pocdsnPhone }}</li>
      </ul>
      <div v-if="filteredPoc.altpocName">
        <p class="">Or their alternate:</p>
        <ul>
          <li><span class="has-text-weight-bold">Name:</span> {{ filteredPoc.altpocName }}</li>
          <li><span class="has-text-weight-bold">Email:</span> {{ filteredPoc.altpocEmail }}</li>
          <li><span class="has-text-weight-bold">Commercial Phone 1:</span> {{ filteredPoc.altpocPhone1 }}</li>
          <li><span class="has-text-weight-bold">Commercial Phone 2:</span> {{ filteredPoc.altpocPhone2 }}</li>
          <li><span class="has-text-weight-bold">DSN:</span> {{ filteredPoc.altpocdsnPhone }}</li>
        </ul>
      </div>
    </ContactInfo>
    

    Added v-if="filteredPoc" which is for error prevention. Even when the modal is not visible, all elements get rendered to the DOM, and if filteredPoc is null (and it is initially), all these elements trying to use it will cause an error, so the v-if will prevent that. The v-if will evaluate to true by the time modalActive is toggled true, so it should all work out.