My code is based on the Michael Tranchida's answer.
Bootstrap 3 html:
<div id="app">
<div v-if="showModal">
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" @click="showModal=false">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Modal title</h4>
</div>
<div class="modal-body">
modal body
</div>
</div>
</div>
</div>
</div>
</transition>
</div>
<button id="show-modal" @click="showModal = true">Show Modal</button>
</div>
Bootstrap 4 html:
<div id="app">
<div v-if="showModal">
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true" @click="showModal = false">×</span>
</button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" @click="showModal = false">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
</div>
</transition>
</div>
<button @click="showModal = true">Click</button>
</div>
js:
new Vue({
el: '#app',
data: {
showModal: false
}
})
css:
.modal-mask {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .5);
display: table;
transition: opacity .3s ease;
}
.modal-wrapper {
display: table-cell;
vertical-align: middle;
}
And in jsfiddle
Bootstrap 5 no longer needs jQuery so it's easier to use with Vue, and no longer requires a library like bootstrap-vue.
Install bootstrap as you would any other JS module in the Vue project using npm install or by adding it to the ...package.json
npm install --save bootstrap
npm install --save @popperjs/core
Next, add the Bootstrap CSS and JS components to the Vue project entrypoint (ie: )...src/main.js
import "bootstrap/dist/css/bootstrap.min.css"
import "bootstrap"
Then, the simplest way to use Bootstrap components is via the attributes. For example here's the Bootstrap Collapse component...data-bs-
<button
class="btn btn-primary"
data-bs-target="#collapseTarget"
data-bs-toggle="collapse">
Bootstrap collapse
</button>
<div class="collapse py-2" id="collapseTarget">
This is the toggle-able content!
</div>
Demo with Navbar component
Or, you can import any Bootstrap components and "wrap" them as Vue components. For example here's the Popover component...
import { Popover } from bootstrap;
const popover = Vue.component('bsPopover', {
template: `
<slot/>
`,
props: {
content: {
required: false,
default: '',
},
title: {
default: 'My Popover',
},
trigger: {
default: 'click',
},
delay: {
default: 0,
},
html: {
default: false,
},
},
mounted() {
// pass bootstrap popover options from props
var options = this.$props
var ele = this.$slots.default[0].elm
new Popover(ele,options)
},
})
<bs-popover
title="Hello Popover"
content="This is my content for the popover!"
trigger="hover">
<button class="btn btn-danger">
Hover for popover
</button>
</bs-popover>
Demo | Read more
This works just fine:
HTML:
<div id="app">
<ul>
<li v-for="item in items">
{{ item.first_name }}
<b-button size="sm" v-b-modal="'myModal'" user="'item'" click="sendInfo(item)">
Saluta {{item.first_name}}
</b-button>
</li>
</ul>
<b-modal id="myModal">
Hello {{selectedUser.first_name}} {{selectedUser.last_name}} !
</b-modal>
</div>
JAVASCRIPT:
new Vue({
el: '#app',
data: {
items :
[
{ first_name: 'Dickerson', last_name: 'Macdonald' },
{ first_name: 'Larsen', last_name: 'Shaw' },
{ first_name: 'Geneva', last_name: 'Wilson' },
{ first_name: 'Jami', last_name: 'Carney' }
],
selectedUser: '',
},
methods: {
sendInfo(item) {
this.selectedUser = item;
}
}
})
What it does is:
1) Execute a method named sendInfo
2) That methods will set the variable inside data with the selected user which information is sent thanks to the selectedUser directive depending on the v-on:click (@click) iteration. Because of that, each button will send the right information.v-for
3) Display the information inside the modal
You need data-toggle and data-target on the button:
<div class="d-flex justify-content-between">
<span class="d-block">These students cannot be in the same group:</span>
<button data-target="#myModal" data-toggle="modal" @click="showModal = true" class="btn btn-outline-primary btn-sm">Add constraint group</button>
</div>
See: https://getbootstrap.com/docs/4.0/components/modal/#via-data-attributes
Since the modal is controlled via some bootstrap internals, I do not think you need the and v-if handler.@click
You just need to reorder your components so that the button is inside the first modal but the second modal should be outside so that it doesn't get closed with the first modal ..
<div>
<b-btn v-b-modal.modal1>Launch demo modal</b-btn>
<b-modal id="modal1" title="Bootstrap-Vue">
<b-btn v-b-modal.modal2>Launch another modal</b-btn>
</b-modal>
<b-modal id="modal2" title="Bootstrap-Vue">
Vueception
</b-modal>
</div>
check this working example
I was looking at the bootstrap-vue test on github as Troy suggested (https://github.com/bootstrap-vue/bootstrap-vue/blob/dev/src/components/modal/modal.spec.js)
There you can see that they are using the prop . Adding this to my code solved my problem.static: true
<b-modal
v-model="showModal"
id="myModal"
data-qa="importModal"
:static="true"
>
</b-modal>
it ('opens a modal', (done) => {
const button = wrapper.find('[data-qa="button"]');
const modal = wrapper.find('#myModal');
expect(button.exists()).toBe(true);
expect(button.is('button')).toBe(true);
expect(modal.exists()).toBe(true);
expect(modal.is('div')).toBe(true);
expect(modal.isVisible()).toBe(false);
button.trigger('click');
Vue.nextTick(() => {
expect(modal.isVisible()).toBe(true);
done();
});
});
I had to select the modal by because the inner part is getting id. When I put a display: none on the modal it sticks on the outer element which is not hidden itself. Another solution for that would be to select it the following way:
data-qaconst modal = wrapper.find('[data-qa="modal"] .modal');
But I still get the following warning in my console:
[BootstrapVue warn]: observeDom: Requires MutationObserver support.
when you looking to bootstrap modal how work with jquery
you will find they add a show class to the modal and change the style of the modal
from to style="display: none"style="display:block"
and a div append to the body
and this div is black overlay background behind the modal<div class="modal-backdrop fade show"></div>
so to do that you can do something like this:
<template>
<div>
<button type="button" class="btn btn-primary" @click="toggleModal">My Modal</button>
<div
ref="modal"
class="modal fade"
:class="{show, 'd-block': active}"
tabindex="-1"
role="dialog"
>
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Modal title</h5>
<button
type="button"
class="close"
data-dismiss="modal"
aria-label="Close"
@click="toggleModal"
>
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<p>Modal body text goes here.</p>
</div>
</div>
</div>
</div>
<div v-if="active" class="modal-backdrop fade show"></div>
</div>
</template>
<script>
export default {
data() {
return {
active: false,
show: false
};
},
methods: {
/**
* when clicking on button in bootstrap
* the modal style set to display and after that a show class add to modal
* so to do that we will show modal-backdrop and set modal display to block
* then after that we will add show class to the modal and we will use setTimeout
* to add show class because we want show class to add after the modal-backdrop show and modal display change
* to make modal animation work
*
*/
toggleModal() {
const body = document.querySelector("body");
this.active = !this.active;
this.active
? body.classList.add("modal-open")
: body.classList.remove("modal-open");
setTimeout(() => (this.show = !this.show), 10);
}
}
};
</script>
codesandbox demo
hope this can help you