How can i close the vue popover when i scroll the screen - vue.js

I haven't decided any popover for Vue.
Device is Touch devices
For touch devices I need click event for opening of popover.
Scenario:
I used Vue bootstrap popover or tooltip
it is stuck to the screen when I am scrolling.
I need to remove when scrolling

You can use this snippet:
new Vue({
el: "#app",
methods: {
do_sth() {
this.$root.$emit('bv::hide::popover')
}
},
created () {
window.addEventListener('scroll', this.do_sth);
},
});
body .wrapper {
padding: 100px 20px;
min-height: 2000px;
}
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap#4.5.3/dist/css/bootstrap.min.css" />
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.min.js"></script>
<div id="app">
<div class="wrapper">
<b-button
href="#"
tabindex="0"
v-b-popover.click="'Popover content'"
title="Popover title"
>
Link button with popover directive
</b-button>
</div>
</div>

Related

How to invoke some method on Bootstrap Vue <b-modal> X-close button

Using b-modal Bootstrap Vue component, I'am trying to invoke especific method when the user clicks on the 'X' button at the right corner of the modal window.
I've tried with #close, #closeHeader, #closeheader without success.
<b-modal ok-only #ok="methodOk" #close="methodClose">
<span>Window closed</span>
</b-modal>
The #close event is what you're after.
If it isn't working for you, i suggest you check your version of BootstrapVue, or potential errors in your console.
new Vue({
el: '#app',
methods: {
onClose() {
alert('Modal X button pressed');
}
}
})
<link href="https://unpkg.com/bootstrap#4.5.3/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.js"></script>
<div id="app">
<b-btn v-b-modal.my-modal>Open Modal</b-btn>
<b-modal id="my-modal" #close="onClose">
Click the `X` top right to see an alert.
</b-modal>
</div>

Add toggle property in v-b-popover for touch

I am using v-b-popover.
My devices are touch and mouse events.
So I am using v-b-popover.hover as a tag.
So I wanted to know, Is their anyway I can toggle the popover(show and hide) in both touch and mouse events.
<b-col v-for="lesson in Lessons">
<b-button
v-b-popover.hover.bottom="lesson.lessonName">
{{lesson.lessonName}}
</b-button>
</b-col>
The tooltip's hover trigger, includes touch on mobile by default. So it should already work with no changes if all you need is touch events on mobile, and hover on desktop.
<b-button v-b-popover.hover="'Hello World!'">
A tooltip is shown on hover on desktop, and touch on mobile.
</b-button>
If you want to support mouse clicks on desktop, you'll need an additional trigger. Either click or focus should work for that.
<b-button v-b-popover.hover.click="'Hello World!'">
A tooltip is shown on hover/click on desktop, and click on mobile.
</b-button>
You can use the v-b-popover.hover.focus.bottom directive for your buttons and then all your button can be triggered by click or hover, and it meets your requirements in mobile devices and mouse events,
new Vue({
el: '#app',
mounted() {
document.getElementsByTagName('body')[0].addEventListener('click', e => {
this.$root.$emit('bv::hide::popover')
});
}
})
#app {
margin: 2rem;
}
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap#4.5.3/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.css" />
<script src="https://unpkg.com/vue#2.6.12/dist/vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.21.2/dist/bootstrap-vue.min.js"></script>
<div id="app">
<b-button v-b-popover.hover.focus.bottom="'Hellow World!'" variant="info">Your Button</b-button>
</div>

How can a Bootstrap-vue tooltip text be changed conditionally?

How can a Bootstrap-vue tooltip text be changed conditionally by a checkbox? How can the tooltip text be accessed to change it? Any help would be greatly appreciated.
Vue component where a checkbox is attempting to change a tooltip:
<template>
<div class="text-center">
<b-button v-b-tooltip.hover.right="tooltipText" variant="outline-primary">
<div v-bind:class="{ active: checkbox1 }">
{{ username }}
</div>
</b-button>
</div>
</template>
<script>
export default {
props: ['username', 'checkbox1'],
data() {
return {
show: true,
tooltipTextContent: 'hello tooltip',
}
},
methods: {
tooltipText() {
if (!this.checkbox1) {
return this.tooltipTextContent
} else {
return `${this.tooltipTextContent} changed`
}
}
},
}
</script>
<style scoped>
.active {
color: red;
}
</style>
You just have to bind a value to the tooltip text that can be changed, like computed:
new Vue({
el: "#app",
data: {
username: 'Username1',
checkbox1: false,
tooltipTextContent: 'block'
},
computed: {
tooltipText() {
if (!this.checkbox1) {
return this.tooltipTextContent
} else {
return `${this.tooltipTextContent} changed`
}
}
}
})
.active {
color: red;
}
<!-- Load required Bootstrap and BootstrapVue CSS -->
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.css" />
<!-- Load polyfills to support older browsers -->
<script src="//polyfill.io/v3/polyfill.min.js?features=es2015%2CIntersectionObserver" crossorigin="anonymous"></script>
<!-- Load Vue followed by BootstrapVue -->
<script src="//unpkg.com/vue#latest/dist/vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.js"></script>
<!-- Load the following for BootstrapVueIcons support -->
<script src="//unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue-icons.min.js"></script>
<div id="app">
<div class="text-center">
<b-button v-b-tooltip.hover.right="tooltipText" variant="outline-primary">
<div v-bind:class="{ active: checkbox1 }">
{{ username }}
</div>
</b-button>
</div>
<b-form-checkbox id="checkbox-1" v-model="checkbox1" name="checkbox-1">
Change tooltip text?
</b-form-checkbox>
</div>

Leaflet map not loading in Bulma tab using Vue.js

I have an issue with loading Leaflet map using Vue.js and Bulma tab components (via Buefy).
If map is placed inside tab then it does not load all tiles until browser window is resized.
If map is placed outside of Bulma tabs component then it loads without any issue.
Calling map.invalidateSize() seems to help, but to do it automatically when tab changes I have to call it using setTimeout and put very big delay, like 1sec - which is very ugly.
How to get this working without this invalidateSize workaround?
Example with the issue: https://codepen.io/alxxnder/pen/zyYxwd
Example without the issue: https://codepen.io/alxxnder/pen/LMYEjr
Code:
new Vue({
el: '#app',
data: {
map: null,
},
methods: {
invalidateSize: function() {
this.map.invalidateSize();
}
},
mounted() {
this.map = L.map('map').setView([38.63, -90.23], 12);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(this.map);
}
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Leaflet Test</title>
<link rel="stylesheet" href="https://unpkg.com/buefy#0.7/dist/buefy.min.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css">
</head>
<body>
<div class="section">
<div class="container" id="app">
<b-tabs position="is-centered">
<b-tab-item label="Tab 1">
<div class="section">
Tab 1
<div class="map" id="map" style="height: 400px; width: 100%"></div>
<button class="button is-info" #click="invalidateSize()">invalidateSize</button>
</div>
</b-tab-item>
<b-tab-item label="Tab 2">
<div class="section">
Tab 2
</div>
</b-tab-item>
</b-tabs>
</div>
</div>
</body>
<script src="https://unpkg.com/vue#2"></script>
<script src="https://unpkg.com/buefy#0.7/dist/buefy.min.js"></script>
<script src="https://unpkg.com/leaflet#1.3.4/dist/leaflet.js"></script>
</html>
As explained in Data-toggle tab does not download Leaflet map, the issue is caused by the fact that your map container does not have yet its full size when you initialize it. You may understand it more easily if your map had been in an initially hidden tab (e.g. in tab 2).
As for your initially active tab (i.e. tab 1), it is probable that Buefy / Bulma still takes some time to reveal the tab content.
Since there is no event when the tab transition completes, you have to wait for the transition duration before calling the invalidateSize method. In your case, 300ms seems to be fine.
Then you should also call it again when the user changes the tab (see Buefy tabs events), otherwise should the browser had changed size while your tab was hidden, the same issue would happen again.
Demo with maps in the 2 tabs:
new Vue({
el: '#app',
data: {
map: null,
map2: null,
tabMaps: []
},
methods: {
invalidateSize: function(tabIndex) {
setTimeout(() => {
if (typeof tabIndex === "number") {
this.tabMaps[tabIndex].invalidateSize();
} else {
// invalidate all maps
this.tabMaps.forEach(map => {
map.invalidateSize();
});
}
}, 300);
}
},
mounted() {
this.map = L.map('map').setView([38.63, -90.23], 12);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(this.map);
// map2 in tab2
this.map2 = L.map(this.$refs.map2).setView([38.63, -90.23], 12);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png").addTo(
this.map2
);
this.tabMaps.push(this.map); // 0
this.tabMaps.push(this.map2); // 1
this.invalidateSize();
}
})
<link rel="stylesheet" href="https://unpkg.com/buefy#0.7/dist/buefy.min.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.3.4/dist/leaflet.css">
<div class="section">
<div class="container" id="app">
<b-tabs #change="invalidateSize" position="is-centered">
<b-tab-item label="Tab 1">
<div class="section">
Tab 1
<div class="map" id="map" style="height: 400px; width: 100%"></div>
<button class="button is-info" #click="invalidateSize()">invalidateSize</button>
</div>
</b-tab-item>
<b-tab-item label="Tab 2">
<div class="section">
Tab 2
<div class="map" ref="map2" style="height: 400px; width: 100%"></div>
</div>
</b-tab-item>
</b-tabs>
</div>
</div>
<script src="https://unpkg.com/vue#2"></script>
<script src="https://unpkg.com/buefy#0.7/dist/buefy.min.js"></script>
<script src="https://unpkg.com/leaflet#1.3.4/dist/leaflet.js"></script>

Vuetify transitions: How to set the transition speed

I have an <audioplayer> component that I would like to be displayed slowly sliding from the bottom of a parent component.
I defined it inside <v-slide-y-transition>, but how I can make it slide slowly from the bottom? I cannot find any attributes to be defined for the <v-slide-y-transition> Vuetify component.
<v-parallax src="img/hero.jpeg">
<v-layout column align-center justify-center>
<img src="#/assets/images/logo.png" height="200">
<h1 class="mb-2 display-1 text-xs-center">HEADER 1</h1>
<h2 class="mb-2 display-1 text-xs-center">HEADER 2</h2>
<div class="subheading mb-3 text-xs-center">SUB-HEADER</div>
<v-btn round #click="switchAudioPlayer()" large href="#">LISTEN</v-btn>
<v-slide-y-transition>
<audioplayer id="audioplayer" v-if="listening" v-show="showAudioPlayer" :autoPlay="autoPlay" :file="audioFile" :canPlay="audioReady" :ended="switchAudioPlayer"></audioplayer>
</v-slide-y-transition>
</v-layout>
</v-parallax>
Vuetify transitions don't appear to have configuration properties, so you'd have to create your own in order to tweak the timing.
You could use a Vue <transition> component, using CSS transition property to set the timing of the animation.
For example, the following CSS sets the duration of the slide-fade animation to 2 seconds.
.slide-fade-enter-active {
transition: all 2s ease;
}
Demo:
new Vue({
el: '#app',
data: () => ({
show: false,
}),
})
.slide-fade-enter-active {
transition: all 2s ease;
}
.slide-fade-leave-active {
transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active below version 2.1.8 */ {
transform: translateY(30px);
opacity: 0;
}
footer {
position: absolute;
bottom: 0;
}
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<button v-on:click="show = !show">
Toggle
</button>
<footer>
<transition name="slide-fade">
<p v-if="show">hello</p>
</transition>
</footer>
</div>
If you use Vue 2.2.0+ the transition component has a duration prop so, it would look like this (if you use the vuetify transition name from your question):
<transition appear name="slide-y-transition" :duration="{ enter: 500, leave: 800 }>
Note: I noticed that you could add duration property to vuetify transition components. Its value is in milliseconds. But it's not very accurate, so I use it along with some CSS as below.
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
show: false,
}),
})
p {
background: lightgreen;
}
.slide-x-transition-enter-active {
background-color: #b2fab2;
transition: background-color 2s, all 2s;
}
.slide-x-transition-enter-to {
background-color: white;
}
.slide-x-transition-leave-active {
background-color: white;
transition: background-color 2s, all 2s;
}
.slide-x-transition-leave-to {
background-color: #fccece;
}
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<v-app id="app">
<button v-on:click="show = !show">
Toggle
</button>
<v-slide-x-transition duration="2000">
<p v-if="show">hello</p>
</v-slide-x-transition>
</v-app>