Bootstrap 3 Modal doesnt show with vue 2 - twitter-bootstrap-3

I am using vue2 and bootstrap 3 and I want to display a modal containing a form. I have the following code in my UsersPage.vue
<b-btn variant="primary" #click="displayAddUser" >
Add user
</b-btn>
<!-- Modal Component -->
<b-modal id="editModal" :title="editModalTitle" :visible="displayEditModal">
<form #submit.stop.prevent="submit">
<div class="form-group">
<b-form-input type="text" placeholder="Enter name" v-model="user.name"/>
</div>
</form>
</b-modal>
In my <script> section I have this:
<script>
export default {
data: () => ({
displayEditModal: false,
editModalTitle: 'Add user'
}),
methods: {
displayAddUser() {
this.displayEditModal = true
this.editModalTitle = 'Add user'
},
... rest of the code
I have also tried using this button with v-b-modal:
<b-btn v-b-modal.editModal>Open</b-btn>
That didn't work either. I tried vue strap. That worked however when the modal closed I got an error saying something about two-way binding not working any more in vue2. I left react because that was the most impossible piece of software I have ever used and I thought vuejs would be simpler.
How can I get a simple modal or b-modal to show???
Update:
I think I have discovered a bug in vue2 or bootstrap. When I put this in my styling then the modal shows:
.modal-open {
opacity: 0.6 !important;
}
.modal-open .modal {
opacity: 0.9 !important;
}

Related

Showing a spinner in vue js and bootsrap using v-show

I am using vue js 2.5.17 and vue router as front end and laravel as back end. I have a table with over 1000 record so before it shows I want to use a spinner or loader to show the progress. I have managed to use spinner-grow from bootstrap but it keeps showing even when the data is displayed. What I am doing wrong.
In the template I have this:
<div v-show="isloading=true" >
<div class="spinner-grow" role="status">
<span class="sr-only">Loading...</span>
</div>
In data if I have
isloading:true,
In my method i have
loadUser(){
axios.get("api/customer").then((
{data})=>(
this.users=data));
this.isloading=false;
console.log(this.isloading);
},
I think you could try something like this
data() {
return {
isloading: false, // default value
};
},
<div v-show="isloading" >
<div class="spinner-grow" role="status">
<span class="sr-only">Loading...</span>
</div>
loadUser(){
this.isloading=true; // make it true to show the loading
axios.get("api/customer").then((
{data})=>(this.users=data));
this.isloading=false; // then hide it here
console.log(this.isloading);
},
try change this <div v-show="isloading=true" > to this <div v-if="isloading" >

Prevent Bootstrap-Vue Modal From Opening

I am using the Bootstrap-Vue modal and want to stop it from opening at times. I'm not sure with how to block the default behavior.
<b-img
ref='cal-modal-button'
id='cal-modal-button'
class="cal-icon"
v-bind:src="imagePath + calimage"
v-b-modal.date-time-modal
>
</b-img>
And then the stripped down modal is set up as such:
<b-modal id="date-time-modal" name="header-modal" ref="date-time-modal" hide-footer title="Set Date and Time">
...
</b-modal>
Is there a way to prevent it from popping up without using JQuery?
From the documentation you can cancel modal by using show event :
<template>
// ...
<b-modal #show="onShow" ... />
</template>
<script>
export default {
// ...
data:() => ({
modalDisabled:true
}),
methods: {
onShow(bvModalEvt) {
if(this.modalDisabled) {
bvModalEvt.preventDefault()
}
}
}
}
</script>
show event reference :
https://bootstrap-vue.js.org/docs/components/modal/#comp-ref-b-modal-events
Always emits just before modal is shown. Cancelable
BvModalEvent object. Call bvModalEvt.preventDefault() to cancel show

Is there a way, to "emit" a built in event, by hard coding it in Vue instance?

I would like to link two components with each other in my Vue project.
I use two-way binding for that, so I have a parent, and two child components.
The concept:
We see a carousel in the left side of the screen, and we see an accordion in the right side. I built the carousel and the accordions with v-for from a database file.
When I click in some of the accordion it drops down, and I need a reaction from a carousel component, to slide exactly there, where I clicked in the accordion.
Like:
carousel: banana, apple, house
accordion: banana, apple house
So when im clicking in the apple accordion button, I need the slider to go to the where are the apple is displayed, and reverse.
As I said, I already bind the two components to each other, so when I'm clicking one of the accordion buttons like #click="onShowStart(index)", I get that index in the another child too, and it's changing dynamically vica-versa by sliding or clicking. So the indexes are already linked and its dynamic.
My problem is I don't know how to trigger an event, like #sliding-start from vue instance in the watch field. So I watch the "actualPosition" prop in my component, and when its changed (from 3 to 1 for example), I would like to start a sliding event to the new value of the actualPosition.
So i need something like:
this.$emit('sliding-start', actualPosition);
I've been sitting at this problem for days, but I think my whole thinking is wrong. But before i believe this, im asking you first.
Here is my code for the Parent component:
<div class="row">
<carousel :actualPosition="actualPosition" class="col bg-dark" #sendTheCarouselPosition="updateAccordion($event)"></carousel>
<accordion :actualPosition="actualPosition" class="col bg-dark" #sendTheAccordionlPosition="updateCarousel($event)"></accordion>
</div>
<script>
export default {
data() {
return {
actualPosition: null,
}
},
methods:{
updateAccordion: function (updatedAccordion){
this.actualPosition = updatedAccordion;
},
updateCarousel: function(updatedSlider){
this.actualPosition = updatedSlider
}
},
}
</script>
My Accordion component:
<template>
<div role="tablist">
<b-card no-body class="mb-1" v-for="(item, index) in dataForProject">
<b-card-header header-tag="header" class="p-1" role="tab">
<b-button block href="#" v-b-toggle="'accordion-' + index" variant="info" #click="onShowStart(index)" >{{ item.title }}</b-button>
</b-card-header>
<b-collapse :id="'accordion-' + index" visible accordion="my-accordion" role="tabpanel">
<b-card-body>
<div>
<h1>data from Carousel sibling: {{ actualPosition }}</h1>
</div>
<b-card-text>{{ item.content }}</b-card-text>
</b-card-body>
</b-collapse>
</b-card>
</div>
</template>
<script>
import myDataBase from '../data2'
export default {
props:['actualPosition'],
watch:{
actualPosition: function () {
},
},
data() {
return {
dataForProject: myDataBase,
}
},
methods:{
onShowStart: function (accordionIndex) {
this.$emit('sendTheAccordionlPosition', accordionIndex);
},
},
}
</script>
And my Carousel component:
<template>
<div>
<p class="mt-4 text-white">
data from Accordion sibling: {{ actualPosition }}
</p>
<b-carousel
id="carousel-1"
:interval="0"
controls
indicators
background="#ababab"
img-width="1024"
img-height="480"
style="text-shadow: 1px 1px 2px #333;"
ref="slider"
#sliding-start="onSlideStart"
#sliding-end="onSlideEnd"
>
<b-carousel-slide v-for="(item, index) in dataForProject" :id="index" >
<img
slot="img"
class="d-block img-fluid w-100"
width="1024"
height="480"
:src="item.image_url"
alt="image slot"
>
</b-carousel-slide>
</b-carousel>
</div>
</template>
<script>
import myDataBase from '../data2'
export default {
props:['actualPosition'],
watch: {
actualPosition: function () {
},
},
data() {
return {
//slide: 0,
dataForProject: myDataBase,
}
},
methods: {
onSlideStart(slide) {
this.$emit('sendTheCarouselPosition', slide);
},
onSlideEnd(slide) {
},
}
}
</script>
I can get this done by two ways.
1 - Global EventBus
I will create an eventBus and register events on it from any file and listen it anywhere -
import { EventBus } from '#/eventBus'
// simply import it to component which need listen the event
//Register Event where you have your methods - like In your COMP_B_TWO
EventBus.$on('changeValue', () => { this.doSomething() })
// Emit event from another component
EventBus.$emit('changeValue')// Like directly from your COMP_A_TWO
To know how to create a eventBus follow this - Global Event Bus Vue
2 - Use state management - Vuex Follow this link - Vuex
Basically, it will have centralized store for all the components in an application. Whenever you wish to update state you will update to store. And all the other component using that state will react accordingly
Okay, so my whole concept was wrong, and i was wrong about this.
I should have used the v-model for this whole thing. And nothing more.
I added the v-model to the target tags, and my problem is solved.

Modal component in VueJS

I am building a web app. I have few components that are modals (that show data about customers, lessons, ...).
I search a way to show one of the components easily.
And if possible doing lazy loading.
What's the best way to perform this?
Check out conditional rendering, specifically v-if. This would only load the modal if the button is clicked for example.
https://v2.vuejs.org/v2/guide/conditional.html#v-if
Single page component:
<template>
<div>
<div
v-if="showModal"
class="modal">
Stuff
</div>
<button #click="toggleModal">
Toggle Modal
</button>
</div>
</template>
<script>
export default {
data () {
return {
showModal: false
}
},
methods: {
toggleModal() {
this.showModal = !this.showModal
}
},
}
</script>

vue.js - close modal when update

Here is my architecture :
Vue.component('center-view', {
props: ["center"],
template: `
<ul style="border: 1px black solid">
<li>Center : {{ center.name }}</li>
<li v-for="p in center.people">
{{ p }}
<button>Affect this user to another center (modal)</button>
</li>
</ul>`
});
new Vue({
el: "#root",
data: {
centers: []
},
created: function () {
this.refreshData();
},
methods: {
refreshData: function() {
// (actually, an ajax request here)
this.centers = [{
name: "Paris",
people: ["Seb", "Eric"]
},
{
name: "NY",
people: ["Edmond", "Nath"]
}
];
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="root">
<center-view
:center="center"
v-for="center in centers"
></center-view>
</div>
The <button> will be replace by a modal.
Here what I would like:
By default the modal's state is "hidden" and only a button is shown
When the user click on that button, the modal's state becomes
"visible" and the entire modal is shown.
The user can affect the people to another center and validate by clicking a button (in the modal), this button emits an event caught by
root.
The root component make an ajax request to the server to update the affectations.
4.a If this request is succesfull, the root component apply a "refreshData" and the modal is closed
4.b Else, the modal is not shown and an error message is shown in this modal.
I'm stuck at the steps 4.a/b. : the only solution I see is to put the state of all modals in the root component. It seems a bit uggly to me (the root component doesn't care about the modal is visible or not).