how to prevent click to move to the next slide in swiperjs? - javascript

How to cancel the click of the next button in swiper base on my logic?
I use swiperjs in vue base on swiperjs, and I want to prevent the from the user to swipe or click on the button to go the next slide base on the results from my logic function.
I try this - not works.
swiper.on('init', async () => {
swiper.navigation.$nextEl.on('click', (e) => {
if (true /* mylogic() */) { e.preventDefault(); }
});
...
});
and this:
<div #click="onNext" slot="button-next"></div>
...
function onNext(e) {
if (true /* mylogic() */) { e.preventDefault(); }
}
Nothing works - the swiper is still move to the next slide.
How to prevent the click to move to the next slide?
Code on Codesandbox.io

By configuring the swiper options to use .swiper-button-prev to trigger the next swipe, it is taking place before your on-click function onNext().
Essentially you need to prevent swiper firing on the next arrow click, and then implement it yourself with the swiper.slideNext() method.
So. Add a ref to the swiper element, remove the swiper-button-prev class, move you onNext() method to the methods object (where it should be, right?), call the swiper.slideNext() method in your function, if someCondition is true.
codesandbox...
<template>
<div id="app">
<h2>1</h2>
<swiper ref="mySwiper" :options="swiperOption1">
<swiper-slide v-for="(game, index) in jackpotGames" v-bind:key="index">
<div class="game-item game-item__1">
game_id: {{game.game_id}},
<br>
provider: {{game.provider}},
<br>
img: {{game.img}}
</div>
</swiper-slide>
<div class="swiper-button-prev" slot="button-prev">←</div>
<div #click="onNext" class="" slot="button-next">→</div>
<div class="swiper-pagination" slot="pagination"></div>
</swiper>
</div>
</template>
<script>
import { swiper, swiperSlide } from "vue-awesome-swiper";
export default {
name: "App",
components: {
swiper,
swiperSlide
},
data() {
return {
swiperOption1: {
slidesPerView: 4,
slidesPerColumn: 1,
spaceBetween: 16,
freeMode: true,
pagination: {
el: ".swiper-pagination",
type: "progressbar"
},
navigation: {
// nextEl: ".swiper-button-next",
prevEl: ".swiper-button-prev"
},
breakpoints: {
640: {
slidesPerView: 2,
spaceBetween: 8,
pagination: {
el: ".swiper-pagination",
type: "bullets"
},
navigation: {}
}
}
},
jackpotGames: [
// Removed to save space in this answer.
]
};
},
methods: {
onNext(e) {
let someCondition = true;
if (someCondition) {
this.swiper.slideNext();
}
}
},
computed: {
swiper() {
return this.$refs.mySwiper.swiper
}
},
mounted() {
console.log('swiper', this.swiper);
}
};
</script>

Related

How to delay nth child item animation in Vue JS

I want delay animation for another item's directly by Vue Js, not css.
In this moment Vue wait until all items has rendered, and all appear at the same time.
How to do delay by change this.animated = true ?
Item.vue
<template>
<transition name="animation-fade">
<div v-if="this.animated">
{{this.itemProp.content}}
</div>
</transition>
</template>
<script>
export default {
name: 'Item',
props: {
itemProp: Object,
},
data: function() {
return {
animated: false,
loading: true,
};
},
methods: {
delayedShow: function(delay) {
setTimeout(this.toggleItem, delay)
},
},
toggleItem: function() {
this.animated = true;
},
mounted: function() {
this.delayedShow(500);
},
}
</script>
Items are defined in other component and every pass by prop to Item model.
Help me please.

Default click on a button when component loads in vue js

I have a button in vue component within template as follow:
<a href="#" #click="openTab" class="border-red px-8" id="activeSlide" data-target-quote="#yvoefrance">
<img :src="inactive_logo[0]" class="logo" alt="yvoefrance logo" />
</a>
I want it to be clicked by default when components loads after refreshing the page, how can I achieve this? I tried following but didn't work for me.
I thought the right place is created. Can anyone help? Thank you in advance.
export default {
name: "component.showcase",
components: {
// ...
},
data() {
return {
// data here....
};
},
created() {
document.querySelector("#activeSlide").click();
},
mounted() {},
beforeDestroy() {},
computed: {},
methods: {
openTab: function(e) {
e.preventDefault();
const target_tab = e.target.parentElement.dataset.targetQuote;
document.querySelector(target_tab).classList.add("active");
e.target.src = require(`#/assets/img/testimonials/${target_img}_active.png`);
}
}
};
The button should call a method when clicked:
<button #click="someMethod">Show Content</button>
Then you can just call that method programmatically from a lifecycle hook instead of trying to manually trigger a click on the button:
methods: {
someMethod() {
console.log('someMethod called');
}
},
created() {
this.someMethod(); // Run the button's method when created
}
EDIT to match your edit:
You are using DOM manipulation but should manipulate data instead and let Vue handle the DOM. Here is a basic example of how you can do what you want:
new Vue({
el: "#app",
data() {
return {
logos: [
{
urlInactive: 'https://via.placeholder.com/150/000000/FFFFFF',
urlActive: 'https://via.placeholder.com/150/FFFFFF/000000',
isActive: false
},
{
urlInactive: 'https://via.placeholder.com/150/666666/FFFFFF',
urlActive: 'https://via.placeholder.com/150/999999/000000',
isActive: false
}
]
}
},
methods: {
toggleActive(logo) {
logo.isActive = !logo.isActive;
}
},
});
<div id="app">
<a v-for="logo in logos" #click="toggleActive(logo)">
<img :src="logo.isActive ? logo.urlActive : logo.urlInactive" />
</a>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

Vue.js: How to rerun your code whenever you change slides in your vue carousel

I am very new to vue.js and fumbling my way though it, forgive me if my terms are incorrect. I am creating a touchscreen application that needs to be ADA compliant (only the bottom part of the screen is accessible, so i have to use buttons for interaction).
I have a parent component with a carousel creating an array of slides, pulling data from my child component.
parent component HTML
<carousel :navigateTo="selectedListIndex" #pageChange="OnPageChange">
<slide v-for="(member, index) in selectedList" :key="index">
<MemberBioPage :member="member"/>
</slide>
</carousel>
parent component SCRIPT:
export default {
data () {
return {
currentPage: 0
}
},
components: {
MemberBioPage,
Carousel,
Slide
},
computed: {
selectedList () {
return this.$store.state.selectedList
},
selectedListIndex () {
return this.$store.state.selectedListIndex
}
},
methods: {
OnPageChange (newPageIndex) {
console.log(newPageIndex)
this.currentPage = newPageIndex
}
}
}
within my child component, i have bio copy being pulled from my data and arrow buttons that allow you to scroll the text. There is an outer container and an inner container to allow the scrolling and based on the height that the content takes up in the container will determine when the arrows disable or not.
child component HTML:
<div class="member-bio-page">
<div class="bio">
<div class="portrait-image">
<img :src="member.imgSrc" />
</div>
<div class="bio-container">
<div class="inner-scroll" v-bind:style="{top: scrollVar + 'px'}">
<h1>{{ member.name }}</h1>
<div class="description-container">
<div class="para">
<p v-html="member.shortBio"></p>
</div>
</div>
</div>
</div>
<div class="scroll-buttons">
<div>
<!-- set the class of active is the scroll variable is less than 0-->
<img class="btn-scroll" v-bind:class="{ 'active': scrollVar < 0 }" #click="scrollUp" src="#/assets/arrow-up.png">
</div>
<div>
<!-- set the class of active is the scroll variable is greater than the height of the scrollable inner container-->
<img class="btn-scroll" v-bind:class="{ 'active': scrollVar > newHeight }" #click="scrollDown" src="#/assets/arrow-down.png">
</div>
</div>
</div>
</div>
child component SCRIPT:
<script>
export default {
props: [
'member', 'currentPage'
],
data () {
return {
scrollVar: 0,
outerHeight: 0,
innerHeight: 0,
newHeight: -10
}
},
mounted () {
this.outerHeight = document.getElementsByClassName('bio-container')[0].clientHeight
this.innerHeight = document.getElementsByClassName('inner-scroll')[0].clientHeight
this.newHeight = this.outerHeight - this.innerHeight
return this.newHeight
},
methods: {
scrollUp () {
console.log(this.scrollVar)
this.scrollVar += 40
},
scrollDown () {
console.log(this.scrollVar)
this.scrollVar -= 40
},
showVideo () {
this.$emit('showContent')
}
}
}
</script>
I am able to get the height of the first bio i look at, but on page change it keeps that set height. I basically want the code in mounted to be able to rerun based on the index of the slide i am on. I need 'newHeight' to update on each page change. I tried grabbing the 'currentPage' from my parent component using props, but it pulls undefined.
here is all a snippet from my data to show you what data i currently have:
{
index: 12,
name: 'Name of Person',
carouselImage: require('#/assets/carousel-images/image.jpg'),
imgSrc: require('#/assets/bio-page-image-placeholder.jpg'),
shortBio: '<p>a bunch of text being pulled</p>',
pin: require('#/assets/image-of-pin.png')
}
this is also my store just in case
const store = new Vuex.Store({
state: {
foundersList: founders,
chairmanList: chairmans,
selectedList: founders,
selectedListIndex: -1
},
mutations: {
setSelectedState (state, list) {
state.selectedList = list
},
setSelectedListIndex (state, idx) {
state.selectedListIndex = idx
}
}
})
Alright, so this is a good start. Here's a few things I would try:
Move the code you currently have in mounted to a new method called calculateHeight or something similar.
Call the method from your scrollUp and scrollDown methods.
So your final code would look something like this:
export default {
props: [
'member', 'currentPage'
],
data () {
return {
scrollVar: 0,
outerHeight: 0,
innerHeight: 0,
newHeight: -10
}
},
mounted () {
this.calculateHeight();
},
methods: {
calculateHeight() {
this.outerHeight = document.getElementsByClassName('bio-container')[0].clientHeight
this.innerHeight = document.getElementsByClassName('inner-scroll')[0].clientHeight
this.newHeight = this.outerHeight - this.innerHeight
},
scrollUp () {
console.log(this.scrollVar)
this.scrollVar += 40
this.calculateHeight()
},
scrollDown () {
console.log(this.scrollVar)
this.scrollVar -= 40
this.calculateHeight()
},
showVideo () {
this.$emit('showContent')
}
}
}

Swiper.IO pagination dots now showing

for some reason the swiper does not show the pagination for the image casousel that i crated.
It shows up in the dom but with the height of 0. Changing it manually did not do anything. Any ideas?
import Swiper from '../../vendor/swiper.min.js';
export default {
name: 'ImageCarouselBlock',
components: {
MediaImage,
},
props: {
cmsData: {
type: Object,
default: () => {
return {};
},
},
},
mounted() {
let carouselConfig = {};
if (this.cmsData.auto){
carouselConfig = {
spaceBetween: 30,
centeredSlide: true,
autoplay: {
delay: 2000,
disableOnInteraction: false,
},
};
}
else {
carouselConfig = {
spaceBetween: 30,
loop: true,
pagination: {
el: '.swiper-pagination',
},
};
}
const mySwiper = new Swiper('.swiper-container', carouselConfig);
},
computed: {
images() {
return this.cmsData.images.map( image => {
return {
// TODO maybe get something from amplicence that tells how big they want the carousel to be?
imageData : getMediaAndSources(image.name, '1500'),
};
});
},
},
};
And this is the corresponding template. I tried changing the position of where i put the pagination element but nothing worked. I am out of ideas here and i need some help.
<div class="image-carousel-block">
<div class="swiper-container">
<div class="swiper-wrapper">
<div class="swiper-slide" v-for="image in images">
<media-image preload="true" :sources="image.imageData.sources" :media="image.imageData.media" />
</div>
</div>
<div class="swiper-pagination"></div>
</div>
</div>
The culprit was in my vue file.
<template src="./template.html"></template>
<script src="./script.js"></script>
<style lang="stylus" scoped> -- wrong here
#import '../../vendor/swiper.styl'
#import './style.styl'
</style>
Removing "scoped" did the trick for me.

is there any way to unit test a Vue.js transition

I have a Vue component with a transition with a dynamic name. I'm trying to find a way to test that the transition name is set properly based on the props I pass into the component. Here's the component.
<template>
<aside :class="['cw-vue-modal', modalSizeClass]" v-show="showModal && modalName === currentModalName">
<transition :name="`${effect}-${speed}`" :duration="500">
<div class="cw-vue-modal-wrap" v-show="showModal">
<div class="cw-vue-modal-body">
<header>
<h2 v-if="currentModalTitle">{{ currentModalTitle }}</h2>
</header>
<article :class="['cw-vue-modal-content', {'cw-vue-modal-pad' : padContent}]">
<slot name="content"></slot>
</article>
</div>
</div>
</transition>
</aside>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
name: 'cw-modal',
props: {
modalName: {
required: true,
type: String
},
padContent: {
required: false,
type: Boolean
},
modalSize: {
required: false,
type: String
},
effect: {
required: false,
type: String
},
speed: {
required: false,
type: String,
default: 'normal'
},
maskLight: {
required: false,
type: Boolean
}
},
computed: {
...mapGetters(['showModal', 'currentModalName', 'currentModalTitle']),
modalSizeClass() {
if (this.modalSize === 'small') return 'cw-vue-modal-sm';
if (this.modalSize === 'large') return 'cw-vue-modal-lg';
return 'cw-vue-modal-md';
}
},
methods: {
...mapActions(['closeModal'])
}
};
</script>
I'm using mocha with chia and the avoriaz library to write unit test. Here is the test.
it('it adds the slide slow effect', () => {
getters = {
showModal: () => true,
currentModalName: () => 'my-modal',
currentModalTitle: () => null
};
store = new Vuex.Store({getters});
const wrapper = mount(Modal, {
propsData: { modalName: 'my-modal', effect: 'slide', speed: 'slow' },
store,
attachToDocument: true
});
expect($('.cw-vue-modal-wrap')).to.have.class('slide-slow-enter-active');
});
It doesn't seem like the class I expect is being inserted into the dom. Any help would be great.
Thanks
I am not 100% sure about how you would implement it into your project following best practices, but there are constructs in computer science like invariants and assertions.
Like I said, I'm not quite familiar with it either, but here's an idea:
you could use this methodology and insert invisible div's into your DOM while running the tests. For example, you can set a variable to true while doing the animation, then using this variable in v-bind:show="yourVar" inside the div tag and check the visibility of that element within your test.
I also didn't find any "official" way of doing it in the docs, so this workaround may be the way.. at leat that's how I did it when writing other functional tests ;)

Categories

Resources