2

I am trying to link my own custom buttons to a flickity carousel in a nuxt application. My parent component set the default value for the prop direction to left.

<CarouselBase class="w-screen carousel" :direction="direction">
  <items/>
</CarouselBase>

data() {
  return {
    direction: 'left',  
  },

This is the code for my carousel component.

<template>
    <ClientOnly>
        <Flickity
            ref="flickity"
            :key="keyIncrementer"
            class="carousel"
            :class="{ 'carousel--active': active }"
            :options="computedOptions"
        >
            <slot />
        </Flickity>
    </ClientOnly>
</template>

<script>

export default {
    name: 'BaseCarousel',
    props: {
        direction: {
            type: String,
            default: '',
        },
    },
    mounted() {
        if (this.direction === 'right') {
            this.$refs.flickity.next()
        } else if (this.direction === 'left') {
            this.$refs.flickity.previous()
        }
    },
    
}

I have got this file vue-flickity.js in my plugins folder

import Vue from 'vue'
import Flickity from 'vue-flickity'

Vue.component('Flickity', Flickity)

I have got this error message =>

Cannot read properties of undefined (reading 'previous')

I don't know how to fix that...

Maxime
  • 337
  • 2
  • 17
  • Why don't you try to import Flickity from 'vue-flickity' right inside your component instead of the plugin, and adding it to the "components" property? Coz so far it looks like Flickity is not picked up from the plugin for some reason. – Stas Parshin Oct 15 '21 at 20:20
  • What are you trying to do here actually? Swipe the slider on `mounted()`? Shouldn't you use a method with a `@click` as in the docs? What's the point of sliding directly when the component is mounted anyway? – kissu Oct 15 '21 at 20:27
  • @StasParshin this one does not work because the package does not handle SSR and just crashes. We found this out in one of the author's previous questions. – kissu Oct 15 '21 at 20:28
  • I don't want to swipe the slider straight away on mounted but I initialised it to "left" instead of empty string ("") in order to see what happens when the props is "left" for the very simple reason that for now I don't know how to make the carousel rerender when the prop changes value. Anyway, now I have just tried with @click as in the docs and I get the same error message. – Maxime Oct 15 '21 at 20:55
  • You don't actually need to initialize anything here. The internal state of the carousel will handle the `previous` and `next` steps for you. You don't need to make it re-render neither. You could use your Vue devtools, sleevt the element with `$vm0` and manually toggle it, it will properly move. Can you edit your question with what you've tried so far? – kissu Oct 15 '21 at 21:32
  • @kissu I have found the solution. I went with the method `@click` as in the docs but I had to reach flickity through two layers of refs. I posted my own answer below. – Maxime Oct 16 '21 at 12:26

2 Answers2

0

The flickity template ref is not yet available in the mounted hook, as <Flickity> is rendered in the next cycle.

Await the next render cycle with the $nextTick() callback before accessing the template ref in mounted():

export default {
  async mounted() {
    // wait until next render cycle for refs to be available
    await this.$nextTick()

    if (this.direction === 'right') {
      this.$refs.flickity.next()
    } else if (this.direction === 'left') {
      this.$refs.flickity.previous()
    }
  },
}

demo

tony19
  • 125,647
  • 18
  • 229
  • 307
  • I have tried your demo, your carousel is using the buttons provided by flickity. I have commented out the whole async mouted hook and it worked the same. It looks like the direction prop does nothing. – Maxime Oct 16 '21 at 11:23
  • 1
    @Maxime not sure where you saw that you need a direction prop anyway. As I told you, just use the buttons with a `@click` event, as in the documentation. – kissu Oct 16 '21 at 12:00
  • @kissu I did as in the documentation, got rid of the direction prop. – Maxime Oct 16 '21 at 12:49
  • @Maxime Yes. This question was about why `this.$refs.flickity` was undefined in the `mounted` hook. Not about using custom buttons or the `direction` prop, which are in separate questions of yours. – tony19 Oct 16 '21 at 23:14
0

Having the carousel as a component like this

<template>
  <ClientOnly>
    <Flickity ref="flickity">
      <slot />
    </Flickity>
  </ClientOnly>
</template>

export default {
    name: 'BaseCarousel',
}

and using it in my index with my own custom buttons

<template>
  <CarouselBase ref="flickityIndex">
    <items for the carousel/>
  </CarouselBase>
  <button @click="previous">Custom Previous Button</button>
  <button @click="next">Custom Next Button</button>
</template>

export default {
     methods: {
    next() {
      this.$refs.flickityIndex.$refs.flickity.next();
    },
    
    previous() {
      this.$refs.flickityIndex.$refs.flickity.previous();
    }
  }
}

Calling next or previous need to reach flickity through both $refs.

Maxime
  • 337
  • 2
  • 17