Reputation: 41
I am building an application that requires sequencing multiple bootstrap-vue modals. Specifically, a button in a nested component should open the 'manage' modal. The 'manage' modal contains buttons that, when clicked, should close the 'manage' modal and open another modal (e.g. 'edit', 'add', 'complete' etc).
Rather than passing props/emitting events up and down so that these can be triggered from different nested components, I would like to have one value in my store, this.$store.state.general.activeModal
, that determines which modal is showing (if any)
Question: How can I create a set of modals in my main app page that render if a value in the state is changed?
My main app will look like this:
<template>
<app-stuff />
<b-modal id="modal1" />
<b-modal id="modal2" />
<b-modal id="modal3" />
</template>
e.g. modal1 should show when this.$store.state.general.activeModal
gets set to 'modal1' and close when the value is changed to something else.
I tried creating a computed variable "showModal1" that is true when store.etc.activeModal=='modal1'
and false otherwise, then using v-modal="showModal1"
to show/hide the modal, but it just ended up creating two copies of the modal every time the value in the store matched (apparently computed values trigger twice when a value in store is changed?)
Any help would be great!
Upvotes: 3
Views: 3930
Reputation: 386
You could create a computed property for the visibility of each modal, for example:
computed: {
modal1Visible() {
return this.$store.state.activeModal === 'modal1';
}
}
Then set the visible
property of the b-modal:
<b-modal :visible="modal1Visible" id="modal1">
To handle closing modals, you can use the hide
event in combination with a store action or mutation which sets the value of this.$store.state.activeModal
, for example:
<b-modal :visible="modal1Visible"
@hide="$store.commit('activeModalSet', null)"
id="modal1"
</b-modal>
This means if you close the modal via the v-b-modal
directive, the close button, or some other method:
hide
eventactiveModalSet
mutation will be triggered, setting this.$store.activeModal
to null
modal1Visible
computed property will now evaluate to false
visible
property of the modal will be false, so the modal will be hidden.Upvotes: 4
Reputation: 6017
Although not bootstrap-vue, we have had success with Bootstrap Modals with the simple v-if
directive. The modal only shows/renders if the condition is true.
Using Vuex, you can have a computed property for activeModal and a v-if on each modal for v-if="activeModal == 'modalName'"
. In our modals, we used Vue lifecycle mounted
to show our modal, and register an emit (bootstrap-vue might handle that differently...)
$('#' + this.modalId).on('hide.bs.modal', () => {
this.$emit('closeModal')
//this would set the v-if in parent Component to false, un-rendering the modal component
})
Upvotes: 0
Reputation: 461
I would suggest you to use the b-modal
component's methods : .show() and .hide() inside a watcher which will catch your state mutations :
<template>
<div>
<b-modal ref="modal1" id="modal1"></b-modal>
<b-modal ref="modal2" id="modal2"></b-modal>
<b-modal ref="modal3" id="modal3"></b-modal>
</div>
</template>
Don't pay attention to mapGetters, you have to watch your store getters/state. Supposed here that activeModal is your state value.
computed : {
...mapGetters([
'activeModal'
])
},
watch : {
activeModal(newActiveModal, oldActiveModal) {
// If an old value was setted, we want to hide it in anyway.
if (oldActiveModal) this.$refs[oldActiveModal].hide()
// If the new value is falsy, do nothing
if (!newActiveModal) return
this.$refs[newActiveModal].show()
}
}
Upvotes: 0