0
votes

I'm building a "Trello" like application whereby I have boards, lists and cards and data is saved to a real time database in Firebase for testing.

I'm using Bootstrap Vue's modals to toggle the visibility. However, I'm getting a problem...

To start, I have my <b-modal> within a Bootstrap card which has a v-for which fetches a list of cards from a list of lists which are in boards. And i want to show the card's data once clicked within the modal, and if I click another card then it will use the same <b-modal> element but display different data.

With my implementation, I appear to be causing a Maximum call stack size exceeded and literally it errors 5,000 + times crashing the browser, it's not looking good :D

I've done some debugging, and have tried using methods with a return false; to find out what's actually happening, and the modal shows, but when dismissing the modal the modal pops straight up again, thus causing the error.

Below, I attach the relevant code and JS:

HTML Markup

<b-col md="4" v-for="(list, index) in board.lists" :key="list.id">
              <b-card bg-variant="light" header-tag="header" footer-tag="footer">
                <div slot="header" class="mb-0">
                  <b-row>
                    <b-col md="8">
                      <h4 class="mb-0"><b-form-input size="sm" class="mr-sm-2 input-is-editable" type="text" placeholder="Enter list name..." v-model="list.name" /></h4>
                    </b-col>
                  </b-row>
                </div>
                <b-card class="mb-3" v-for="(card, index) in list.cards" :key="card.id" v-b-modal.prevent="modalId(index)">{{ card.name }}
                  <b-modal :id="'modal' + index" hide-footer title="Using Component Methods">
                    <div class="d-block text-center">
                      <h3>{{ card.name }}</h3>
                    </div>
                    <b-button class="mt-3" variant="outline-danger" block>Close Me</b-button>
                  </b-modal>
                </b-card>
                <div slot="footer" class="mb-0">
                  <b-row>
                    <b-col>
                      <b-nav-form>
                        <b-form-input size="sm" class="mr-sm-2" type="text" placeholder="Enter card name..." v-model="cardname" />
                        <b-button size="sm" variant="success" class="my-2 my-sm-0" type="button" @click="addCard(index)" :disabled="!cardname">Add card</b-button>
                      </b-nav-form>
                    </b-col>
                  </b-row>
                </div>
              </b-card>
            </b-col>

JS

export default {
  data () {
    return {
      id: this.$route.params.id,
      board: [],
      cards: [],
      lists: [],
      listname: '',
      cardname: '',
      editedFields: {}
    }
  },
  created() {
    this.$http.get('myfirebaseurl/boards/' + this.id + '.json').then(response => {
      this.board = response.body
    }, response => {
      // handle error for fetching property data.
    });
  },
  methods: {
    modalId(index) {
      return 'modal' + index;
    }
  }
}

There is more to the JS, however I'm only attaching what's relevant to the markup above.

Any suggestions on what I'm doing wrong and how to fix?

enter image description here

many thanks!

1
You probably shouldn't have the modal in a v-for. If you put it at the top of your html you can have an @click event inside a v-for that passes the required data to the modal and opens it.Andrew1325

1 Answers

1
votes

I would rather agree with @Andrew1325 who pointed out that creating a single instance of modal dialog and passing the selected data might be a better option, for example

 <div>
    <div v-for="(item) in items" :key="item.id">
      <b-card
        :title="item.title"
        :img-src="item.imageUrl"
        img-alt="Image"
        img-top
        tag="article"
        style="max-width: 20rem;"
        class="mb-2"
      >
        <b-card-text>{{item.text}}</b-card-text>

        <b-button variant="primary" @click="showModal(item)">Show details</b-button>
      </b-card>
    </div>
    <b-modal id="modal1" :title="selectedItem.title">
      <img style="max-width: 20rem;" :src="selectedItem.imageUrl"/>
      <p class="my-4">{{selectedItem.text}}</p>
    </b-modal>
</div>



export default {
  data() {
    return {
      selectedItem: {},
      items: [
        {
          id: 1,
          title: "First",
          imageUrl : "https://picsum.photos/600/300/?image=23",
          text: "Some quick example text to build on the card title and make up the bulk of the card's content"
        },
        {
          id: 2,
          imageUrl : "https://picsum.photos/600/300/?image=24",
          title: "Second",
          text: "Some quick example text to build on the card title and make up the bulk of the card's content"
        },
        {
          id: 3,
          imageUrl : "https://picsum.photos/600/300/?image=25",
          title: "Third",
          text: "Some quick example text to build on the card title and make up the bulk of the card's content"
        }
      ]
    };
  },
  methods: {
    showModal(item){
      this.selectedItem = item;
      this.$root.$emit("bv::show::modal", "modal1");
    }
  }
};

Demo