How to create Hooper navigation by range slider? - javascript

I need Hooper to change slides depending on what value the frame slider has. That is, if the slider is set to "6", Hooper should switch to slide index "6". I researched the documentation example but my solution doesn't work. Here is the code:
Html:
<div class="range-slider">
<input
class="range-slider__input"
type="range"
min="0"
max="10"
v-model="rangeSliderValue"
/>
<p>{{ rangeSliderValue }}</p>
</div>
<hooper
class="weekly-novelties__slider"
:settings="hooperSettings"
#slide="updateCarousel"
></hooper>
<slide
class="weekly-novelties__slide-container"
v-for="(slide, indx) in slides"
:key="indx"
:index="indx"
>*slide*
</slide>
Script:
<script>
import {
Hooper,
Slide,
Progress as HooperProgress,
Pagination as HooperPagination,
Navigation as HooperNavigation,
} from 'hooper'
import 'hooper/dist/hooper.css'
export default {
name: 'WeeklyNovelties',
components: {
Hooper,
Slide,
},
data() {
return {
rangeSliderValue: 0,
hooperSettings: {
itemsToShow: 3.932,
itemsToSlide: 2,
ref: 'carousel',
navigation: {
type: 'custom',
},
// initialSlide: 2,
// infiniteScroll: true,
},
watch: {
carouselData() {
this.$refs.carousel.slideTo(this.rangeSliderValue)
},
},
methods: {
updateCarousel(payload) {
this.myCarouselData = payload.currentSlide
},
changeSliderValue() {
this.$refs.carousel.slideTo(this.rangeSliderValue)
},
},
}
},
setup() {
const slides = Array.from({ length: 10 }).map(
(el, index) => `Slide ${index + 1}`
)
return {
slides,
}
},
}
</script>
The value of the variable rangeSliderValue is displayed correctly, but when moving the range slider, the carousel does not change slides

Related

Keep vue component events after moving

I have the following vue component
<template>
<div class="box"
:data-target="dropAreaClass"
:class="{ 'js-draggable': isDraggable }"
:id="id"
:draggable="isDraggable"
#dragstart="dragStart"
#dragend="dragEnd">
{{ id }}
</div>
</template>
<script>
export default {
name: 'ActionBox',
props: {
dropAreaClass: {
default: 'js-droppable--any',
type: String,
},
id: {
default: null,
type: String,
required: true,
},
isDraggable: {
default: true,
type: Boolean,
},
},
data: () => ({
dropAreas: null,
}),
mounted() {
this.dropAreas = document.querySelectorAll(`.${this.dropAreaClass}`);
},
methods: {
dragEnd(event) {
this.dropAreas.forEach(dropArea => {
dropArea.classList.remove('drop');
});
event.currentTarget.classList.remove('dragging');
},
dragStart(event) {
this.dropAreas.forEach(dropArea => {
dropArea.classList.add('drop');
});
event.currentTarget.classList.add('dragging');
event.dataTransfer.setData('text', event.currentTarget.id);
},
},
};
</script>
This is a simple div which I can drag a drop into multiple columns in the parent component - once it is dropped in one of the target columns, the following function is fired to move the component to the column it is dropped in:
drop(event) {
const droppedElement = document.getElementById(event.dataTransfer.getData('text'));
if (event.currentTarget.classList.contains(droppedElement.dataset.target)) {
event.currentTarget.prepend(droppedElement);
event.currentTarget.classList.remove('drop');
}
},
This all works fine, however, once it is dropped, I can no longer drag the component to another column as it seems to have lost all it's event bindings. Is there a way to keep the events after dropping?

Vue.js: Vue-Carousel jumping to last item in array on click

I am currently working on an application that involves scrolling through members from two different lists. Once you click one you see their image and bio. We added up and down arrows to scroll through their biography, but when i click the down arrow it seems that the active class on the carousel slide now jumps to the last member in my array, but still displays the member i was already on. To add to that I cannot swipe back and forth once i am on a member (this is something that I could do previously.) I know this probably isn't the best description and there is only so much code I can show, as I cannot display the entire application.
I wanted to also note that if I refresh my page, everything works as expected. Does this mean something isn't initializing correctly?
this is the code specific to the page i am talking about:
<template>
<div class="member-info-carousel">
<div class="header">
<h2 v-if="founderChairman === true">Member List One</h2>
<h2 v-else>Member List Two</h2>
<img src="../assets/logo.png" alt="Logo" />
</div>
<carousel :minSwipeDistance="384" :perPage="1" :paginationEnabled="false" :navigationEnabled="true" navigationNextLabel="<i>NEXT</i>"
navigationPrevLabel="<i>BACK</i>" :navigateTo="selectedListIndex" #pagechange="OnPageChange">
<slide v-for="(member, index) in selectedList" :key="index">
<div class="member-bio-page" :member="member" v-on:showContent="showContent">
<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'}">
<div class="english"></div>
<div class="pin-name">
<img :src="member.pin" />
<h1>{{ member.name }}</h1>
</div>
<div class="description-container">
<div class="para">
<p class="quote" v-html="member.quote"></p>
<p v-html="member.bio"></p>
<div class="spanish"></div>
<p class="quote" v-html="member.spanishQuote"></p>
<p v-html="member.spanishBio"></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 > pageChangeHeight }" #click="scrollDown" src="#/assets/arrow-down.png">
</div>
</div>
<div class="eng-span">
English
Español
</div>
</div>
<div class="play-button">
<!-- if the array members has a property of video, then the play button will show on the slide. If not it will not show the image -->
<img v-if="member.hasOwnProperty('video')" #click="showContent" src="#/assets/play-button.png">
</div>
</div>
<!-- <MemberBioPage :member="member" v-on:showContent="showContent"/> -->
</slide>
</carousel>
<modal name="video-modal"
:width="1706"
:height="960">
<video width="1706" height="960" :src="(selectedList && selectedList[this.currentPage]) ? selectedList[this.currentPage].video : ''" autoplay />
</modal>
<div class="footer-controls">
<div class="footer-bar">
<p>Tap Back or Next to view additional profiles.</p>
<p>Tap the arrows to scroll text up or down.</p>
</div>
<div class="nav-container">
<img class="nav-bubble" src="#/assets/navigation-bubble-bio-page.png" alt="An image where the back, next and close button sit" />
</div>
<button class="close-button" #click="closeInfo">
<img src="#/assets/x-close-button.png" />
CLOSE
</button>
</div>
</div>
</template>
<script>
import { Carousel, Slide } from 'vue-carousel'
export default {
data () {
return {
currentPage: 0,
pageChangeHeight: -10,
scrollVar: 0
}
},
components: {
// MemberBioPage,
Carousel,
Slide
},
mounted () {
this.enableArrows()
},
updated () {
this.enableArrows()
},
computed: {
selectedList () {
return this.$store.state.selectedList
},
selectedListIndex () {
return this.$store.state.selectedListIndex
},
founderChairman () {
return this.$store.state.founderChairman
}
},
methods: {
enableArrows () {
var outerHeight
var innerHeight
if (document.querySelectorAll('.VueCarousel-slide-active').length > 0) {
outerHeight = document.querySelectorAll('.VueCarousel-slide-active .bio-container')[0].clientHeight
innerHeight = document.querySelectorAll('.VueCarousel-slide-active .inner-scroll')[0].clientHeight
} else {
outerHeight = document.querySelectorAll('.VueCarousel-slide .bio-container')[0].clientHeight
innerHeight = document.querySelectorAll('.VueCarousel-slide .inner-scroll')[0].clientHeight
}
this.pageChangeHeight = outerHeight - innerHeight
return this.pageChangeHeight
},
scrollUp () {
this.scrollVar += 40
console.log(this.scrollVar += 40)
},
scrollDown () {
this.scrollVar -= 40
console.log(this.scrollVar)
},
OnPageChange (newPageIndex) {
this.scrollVar = 0
this.currentPage = newPageIndex
this.pageChangeHeight = -10
},
closeInfo () {
if (this.$store.state.selectedList === this.$store.state.foundersList) {
this.$store.commit('setSelectedState', this.$store.state.foundersList)
this.$router.push({ name: 'Carousel' })
} else if (this.$store.state.selectedList === this.$store.state.chairmanList) {
this.$store.commit('setSelectedState', this.$store.state.chairmanList)
this.$router.push({ name: 'Carousel' })
}
},
showContent () {
this.$modal.show('video-modal')
},
toEnglish () {
this.scrollVar = 0
},
toSpanish () {
var spanishPos
if (document.querySelectorAll('.VueCarousel-slide-active').length > 0) {
spanishPos = document.querySelectorAll('.VueCarousel-slide-active .spanish')[0].offsetTop
} else {
spanishPos = document.querySelectorAll('.VueCarousel-slide .spanish')[0].offsetTop
}
this.scrollVar = -spanishPos
}
}
}
</script>
This is my store index file:
import Vue from 'vue'
import Vuex from 'vuex'
import chairmans from '#/data/chairmans-club'
import founders from '#/data/founders-circle'
import memoriam from '#/data/in-memoriam'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
finishedLoading: false,
transitioning: false,
foundersList: founders,
chairmanList: chairmans,
selectedList: founders,
selectedListIndex: -1,
founderChairman: true,
inMemoriam: memoriam,
idleTimer: {
id: null,
duration: 1
},
idleTimeoutModal: {
show: false,
duration: 1
}
},
mutations: {
setSelectedState (state, list) {
state.selectedList = list
},
setSelectedListIndex (state, idx) {
state.selectedListIndex = idx
},
showIdleTimeoutModal (state, value) {
state.idleTimeoutModal.show = value
},
founderChairmanClicked (state, data) {
state.founderChairman = data
},
setInMemoriam (state, content) {
state.inMemoriam = content
}
},
actions: {
restartIdleTimer ({ state, commit }) {
clearTimeout(state.idleTimer.id)
state.idleTimer.id = setTimeout(() => {
commit('showIdleTimeoutModal', true)
}, state.idleTimer.duration * 1000)
},
stopIdleTimer ({ state }) {
clearTimeout(state.idleTimer.id)
}
}
})
export default store
and an example of the data i am pulling:
const event = [
{
index: 0,
name: 'Member Name',
carouselImage: require('#/assets/carousel-images/image.jpg'),
drawerImage: require('#/assets/drawer-images/drawerimage.jpg'),
imgSrc: require('#/assets/bio-images/bioimage.jpg'),
quote: '“quote.”',
spanishQuote: `“spanish quote.”`,
bio: '<p>bio copy here</p>',
spanishBio: '<p>spanish bio copy</p>',
pin: require('#/assets/pin.png')
}
]
export default event

Vue: how to update cart total price when user increment item in child component

So I create this cart page in Vue. I just don't understand how to update the cart page total price when the quantity of the item child component increase or decreases. If the item component quantity increase, of course, the total price must increase too.
Here's my cart parent component :
<template>
<div class="cart-container">
<h1 class="cart-title-page">Keranjang Anda</h1>
<div class="cart-item-container">
<cart-item v-for="(data, i) in cartData" :item="data" :key="i" />
</div>
<div class="cart-total-wrapper">
<div class="total-text-wrapper">
<p>Total</p>
</div>
<div class="total-amount-wrapper">
<p>Rp. 150.000.000</p>
</div>
</div>
</div>
</template>
<script>
import CartItem from '#/components/cart-item'
export default {
data() {
return {
cartData: [
{
product_name: 'vario ZS1',
price: 1000000,
url_thumbnail: 'https://cdn3.imggmi.com/uploads/2019/10/8/9e27ca9046031f6f21850be39b379075-full.png',
color: '#fff'
},
{
product_name: 'vario ZS1',
price: 1000000,
url_thumbnail: 'https://cdn3.imggmi.com/uploads/2019/10/8/9e27ca9046031f6f21850be39b379075-full.png',
color: '#fff'
},
{
product_name: 'vario ZS1',
price: 1000000,
url_thumbnail: 'https://cdn3.imggmi.com/uploads/2019/10/8/9e27ca9046031f6f21850be39b379075-full.png',
color: '#fff'
}
]
}
},
methods: {
getAllCartItem () {
this.$store.dispatch('cart/checkCartItem')
this.cartData = this.$store.state.cart.cartItem
}
},
created () {
this.getAllCartItem ()
},
components: {
'cart-item': CartItem
}
}
</script>
this is my cart item child component:
<template>
<div class="root-cart-item">
<div class="container-cart-left">
<div class="cart-img-wrapper">
<img :src="item.url_thumbnail" />
</div>
<div class="cart-title-wrapper">
<div class="title-wrapper">
<h3>{{ getProductbrand }}</h3>
<p>{{ item.product_name }}</p>
</div>
</div>
</div>
<div class="container-cart-right">
<div class="cart-amount-wrapper">
<number-input v-model="singleCart.amount" :min="1" :max="singleCart.stok" inline center controls></number-input>
</div>
<div class="cart-price-wrapper">
<p>{{ getProductTotalPrice }}</p>
</div>
<div class="cart-delete-wrapper">
<img src="../assets/delete.svg"/>
</div>
</div>
</div>
</template>
<script>
import ProductImage from './product-image'
import VueNumberInput from '#chenfengyuan/vue-number-input';
export default {
props: {
item: {
type: Object,
required: true
}
},
data () {
return {
singleCart: {
stok: 15,
amount: 1,
totalPrice: 0
}
}
},
computed: {
getProductbrand: function () {
let splittedName = this.item.product_name.split(' ')
return splittedName[0]
},
getProductTotalPrice: function () {
var x = this.singleCart.totalPrice.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".")
var totalPrice = `Rp. ${x}`
return totalPrice
}
},
watch: {
'singleCart.amount': {
handler: function () {
this.singleCart.totalPrice = this.singleCart.price * this.singleCart.amount
},
deep: true
}
},
components: {
'product-image': ProductImage,
'number-input': VueNumberInput
}
}
</script>>
and if anyone wondering, this is my cart store:
const state = {
cartItem: []
}
const getters = {
getAllCartItem: (state) => {
return state.cartItem
}
}
const mutations = {
updateCartItem: (state, cart) => {
state.cartItems = cart
}
}
const actions = {
checkCartItem: ({ commit }) => {
let item = JSON.parse(localStorage.getItem('cart'))
if (cart) {
commit('updateCartItem', item)
}
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
like I said, the problem should be quite simple, I just have to update the CSS class .total-amount-wrapper in the parent component, when the quantity in the child component increase or decreases. The total price in the child cart-item component is working, I just have to find a way to count every total price in the child cart-item component, and show it in the parent component.
For update the parent you must use the v-model approach or use the $emit.
In your code you must update the input to use the v-model or you must $emit an event when price change.
The first is simple and you must follow the tutorial you find in the link above, the second is below.
Child Component
watch: {
'singleCart.amount': {
handler: function () {
this.singleCart.totalPrice = this.singleCart.price * this.singleCart.amount
this.$emit("priceChanged", this.singleCart.totalPrice);
},
deep: true
}
}
Parent
<template>
..
<div class="cart-item-container">
<cart-item v-for="(data, i) in cartData" :item="data" :key="i"
#priceChanged="onPriceChanged" />
</div>
</template>
<script>
methods: {
..
onPriceChanged(value) {
this.total += value;
}
}
</scritp>

Implementing sidebar don't displayed

I'm implementing Vue paper dashboard sidebar. So I have something like this:
Into Index I have
<template>
<div>
AdminIndex
<side-bar>
</side-bar>
</div>
</template>
<script>
import { faBox, faImages } from '#fortawesome/fontawesome-free-solid';
import Sidebar from '#/components/sidebar/SideBar';
export default {
name: 'admin-index-view',
components: {
SideBar,
},
data() {
return {
showSidebar: false,
sidebarLinks: [
{
name: 'admin.menu.products',
icon: faBoxes,
route: { name: 'adminProducts' },
},
{
name: 'admin.menu.sliders',
icon: faImages,
route: { name: '/admin/stats' },
},
],
};
},
methods: {
displaySidebar(value) {
this.showSidebar = value;
},
},
};
</script>
SideBar component:
<template>
<div :class="sidebarClasses"
:data-background-color="backgroundColor"
:data-active-color="activeColor">
<!--
Tip 1: you can change the color of the sidebar's background using: data-background-color="white | black | darkblue"
Tip 2: you can change the color of the active button using the data-active-color="primary | info | success | warning | danger"
-->
<!-- -->
<div class="sidebar-wrapper"
id="style-3">
<div class="logo">
<a href="#"
class="simple-text">
<div class="logo-img">
<img src="static/img/vue-logo.png"
alt="">
</div>
Paper Dashboard
</a>
</div>
<slot>
</slot>
<ul :class="navClasses">
<!--By default vue-router adds an active class to each route link. This way the links are colored when clicked-->
<router-link v-for="(link,index) in sidebarLinks"
:key="index"
:to="link.route"
tag="li"
:ref="link.name">
<a>
<font-awesome-icon :icon="link.icon" />
<p v-t="link.name" />
</a>
</router-link>
</ul>
<moving-arrow :move-y="arrowMovePx">
</moving-arrow>
</div>
</div>
</template>
<script>
import FontAwesomeIcon from '#fortawesome/vue-fontawesome';
import MovingArrow from './MovingArrow';
export default {
name: 'side-bar',
components: {
MovingArrow,
FontAwesomeIcon,
},
props: {
type: {
type: String,
default: 'sidebar',
validator: value => {
const acceptedValues = ['sidebar', 'navbar'];
return acceptedValues.indexOf(value) !== -1;
},
},
backgroundColor: {
type: String,
default: 'black',
validator: value => {
const acceptedValues = ['white', 'black', 'darkblue'];
return acceptedValues.indexOf(value) !== -1;
},
},
activeColor: {
type: String,
default: 'success',
validator: value => {
const acceptedValues = [
'primary',
'info',
'success',
'warning',
'danger',
];
return acceptedValues.indexOf(value) !== -1;
},
},
sidebarLinks: {
type: Array,
default: () => [],
},
},
data() {
return {
linkHeight: 60,
activeLinkIndex: 0,
windowWidth: 0,
isWindows: false,
hasAutoHeight: false,
};
},
computed: {
sidebarClasses() {
if (this.type === 'sidebar') {
return 'sidebar';
}
return 'collapse navbar-collapse off-canvas-sidebar';
},
navClasses() {
if (this.type === 'sidebar') {
return 'nav';
}
return 'nav navbar-nav';
},
/**
* Styles to animate the arrow near the current active sidebar link
* #returns {{transform: string}}
*/
arrowMovePx() {
return this.linkHeight * this.activeLinkIndex;
},
},
watch: {
$route() {
this.findActiveLink();
},
},
methods: {
findActiveLink() {
this.sidebarLinks.find((element, index) => {
const found = element.path === this.$route.path;
if (found) {
this.activeLinkIndex = index;
}
return found;
});
},
},
mounted() {
this.findActiveLink();
},
};
</script>
I dont receive any issues or vue errors, sidebar just don't display. In Chrome console just return empty: <side-bar data-v-66018f3c=""></side-bar> Someone knows why sidebar is not binded? What I need to do to get correctly implementation of it? Regards
Chrome console error:
[Vue warn]: Unknown custom element: - did you register the
component correctly? For recursive components, make sure to provide
the "name" option.

Vue2: Animate Items Inside a Slot with Anime.js

Goal
I'd like to stagger the entry of the .modal-slot children.
Problem
I am unable to animate each child node individually, although animating .modal-slot works.
Context
<template>
<transition
:css="false"
#before-enter="beforeEnter"
#enter="enter"
#leave="leave"
#after-leave="afterLeave">
<div class="modal-content">
<div v-if="title" class="modal-title">{{ title }}</div>
<div class="modal-slot">
<slot></slot>
</div>
</div>
</transition>
</template>
<script>
import _ from 'lodash';
import anime from 'animejs';
export default {
name: 'modal',
data () {
return {
delay: 50,
duration: 400,
easing: 'easeInOutBack',
modalBackground: null,
modalTitle: null,
modalSlotElements: null,
modalClose: null
};
},
methods: {
beforeEnter (element) {
// Correctly logs selected '.modal-slot' children
console.log('modalSlotElements', this.$data.modalSlotElements);
_.forEach(this.$data.modalSlotElements, element => {
element.style.opacity = 0;
element.style.transform = 'translateY(10px)';
});
},
enter (element, done) {
anime({
targets: this.$data.modalSlotElements,
duration: this.$data.duration,
easing: this.$data.easing,
delay: (target, index) => this.$data.delay * (index + 1),
translateY: 0,
opacity: 1,
complete: () => { done(); }
});
}
},
mounted () {
// I can select '.modal-slot' and the animation works as intended. Looking for its children breaks the animation.
this.$data.modalSlotElements = document.querySelectorAll('.modal-slot > .action-card');
}
};
</script>
It is a scope issue. My solution is to apply the animations to those elements in the component in which they are defined, not the component into which they are slotted.

Categories