Search code examples
vue.jsbootstrap-modalbootstrap-vue

Bootstrap-Vue Modal: How to open different modals in an V-For rendered list?


I am using Bootstrap-Vue Modals to open an "Edit" modal when clicking the "Edit" button that is attached to each item I have rendered in a list from v-for rendered list.

Each time, however, when I click on the edit button, it opens all of the modals, stacked on top of eachother with the last element in the list being the top modal.

How can I specify it to only open the modal/information for the item that is clicked to be edited?

//Parent Component

<div class="dataList">
 <div v-bind:key="item.id" v-for="item in this.$store.getters.data">
    <Child v-bind:item="item"></Child>
 </div>
</div>



//Child Component
<div>
      {{this.item.name}}
      {{this.item.details}}
      {{this.item.completedBy}}
      {{this.item.status}}
      <button v-b-modal.modal-1>Edit</button>
      <button v-on:click="deleteItem">Delete</button>

      <div>
        <b-modal id="modal-1" title="BootstrapVue">
          <form @submit="editItem">
              <input v-model="name">
              <input v-model="details">
              <input v-model="completedBy">
              <select v-model="status">
                  <option>Fail</option>
                  <option>Warn</option>
                  <option>Pass</option>
              </select><br>
              <input type="submit" value="Submit" @click="$bvModal.hide('modal-1')">
          </form>
        </b-modal>
      </div>
  </div>


Now each modal shows the correct information (like the proper name, details, status, etc), but I just need it only the specific modal.

I imagine it has something to do with the 'v-b-modal.modal-1' but I'm not sure how to dynamically set the id of each modal...is there a way to easily set each modal id to match the item.id?

Here is the documentation for Bootstrap-Vue Modals, but I wasn't to find what I needed.


Solution

  • I'd recommend moving the <b-modal> out of your v-for. This way you only have one.

    Then you instead set the user/item you want to edit to a variable, and utilize that in your modal to show the data for the selected user.

    Example

    new Vue({
      el: "#app",
      data() {
        return {
          selectedUser: null,
          items: [{
              name: "Name 1",
              status: "Fail",
              details: "Details 1"
            },
            {
              name: "Name 2",
              status: "Warn",
              details: "Details 2"
            }
          ]
        }
      },
      methods: {
        editUser(user) {
          this.selectedUser = user;
          this.$bvModal.show("edit-modal");
        }
      }
    })
    <link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap@4.5.3/dist/css/bootstrap.min.css" />
    <link href="https://unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.css" rel="stylesheet" />
    
    <script src="//unpkg.com/vue@2.6.12/dist/vue.min.js"></script>
    <script src="//unpkg.com/bootstrap-vue@2.21.2/dist/bootstrap-vue.min.js"></script>
    
    
    <div id="app" class="p-4">
      <div v-for="item in items" class="mt-3">
        {{item.name}} {{item.details}} {{item.status}}
    
        <b-btn variant="primary" @click="editUser(item)">Edit</b-btn>
        <b-btn variant="danger">Delete</b-btn>
      </div>
      <b-modal id="edit-modal" title="Edit User">
        <form v-if="selectedUser">
          <input v-model="selectedUser.name">
          <input v-model="selectedUser.details">
          <input v-model="selectedUser.completedBy">
          <select v-model="selectedUser.status">
            <option>Fail</option>
            <option>Warn</option>
            <option>Pass</option>
          </select><br>
          <input type="submit" value="Submit">
        </form>
      </b-modal>
    </div>

    If you want to keep the modal inside your v-for, you will have to give it a unique id. If you item has one i would recommend using that, otherwise you can use the index from the v-for.

    Simplified example

    <div v-for="item in items">
      <button v-b-modal:[`edit-modal-${item.id}`]>Edit Item</button>
     
      <b-modal :id="`edit-modal-${item.id}`">
        <!-- Modal Content-->
      </b-modal>
    </div>