vue.jsnuxt.jsvue-flickity

vue-flickity: how to get selectedIndex into vue data


I'm using vue-flickity for a carousel. There's a <flickity /> component (the carousel), a <p> tag with data {{ selectedIndex }}, and a button which gets the current slide number from flickity, and updates selectedIndex.

How can I automatically update selectedIndex with the current slide index when a user scrolls left or right (i.e. calls Next/Previous methods)? I'm struggling to "hook into" those methods of the module.

I can define a method Next() and bind that to a button, but it doesn't update when a user scrolls.

EDIT: I've managed to hook into on.change (using mounted). console.log shows me the correct selectedInde now, but this isn't reacting down to where it says "You are at Slide number {{ selectedIndex }}"

<template>
  <div>
    <flickity ref="flickity" :options="flickityOptions">
      <div class="carousel-cell">1</div>
      <div class="carousel-cell">2</div>
      <div class="carousel-cell">3</div>
      <div class="carousel-cell">4</div>
      <div class="carousel-cell">5</div>
    </flickity>
    <p>You are at Slide number {{ selectedIndex }}</p>
    <button @click="manualUpdate()">Update</button>
  </div>
</template>

<script>
import Flickity from 'vue-flickity'

export default {
  components: {
    Flickity
  },
  data() {
    return {
      flickityOptions: {
        initialIndex: 0,
        prevNextButtons: false,
        pageDots: false,
        wrapAround: true
      },
      selectedIndex: 0
    }
  },
  methods: {
    manualUpdate() {
      this.selectedIndex = this.$refs.flickity.selectedIndex();
      console.log(this.selectedIndex)
    },
  },
  mounted() {
    this.$refs.flickity.on('change', function (event) {
      this.selectedIndex = event
      console.log(this.selectedIndex)
    })
  }
}
</script>

<style>
/* external css: flickity.css */

* {
  -webkit-box-sizing: border-box;
  box-sizing: border-box;
}

.carousel-cell {
  width: 80%;
  min-height: 50vh;
  max-height: 80vh;
  object-fit: contain;
  margin-right: 10px;
}
</style>

Solution

  • As explain on this Github issue, you need to bind the listener on the init event.
    The end result looks like this:

    <template>
      <div>
        <flickity ref="flickity" :options="flickityOptions" @init="onInit">
          <div class="carousel-cell">1</div>
          <div class="carousel-cell">2</div>
          <div class="carousel-cell">3</div>
          <div class="carousel-cell">4</div>
          <div class="carousel-cell">5</div>
        </flickity>
        <p>You are at Slide number {{ selectedIndex }}</p>
        <button @click="goToPrevious">Previous</button>
        <button @click="goToNext">Next</button>
      </div>
    </template>
    
    <script>
    import Flickity from 'vue-flickity'
    
    export default {
      components: {
        Flickity,
      },
      data() {
        return {
          flickityOptions: {
            initialIndex: 0,
            prevNextButtons: false,
            pageDots: false,
            wrapAround: true,
          },
          selectedIndex: 0,
        }
      },
      methods: {
        goToNext() {
          this.$refs.flickity.next()
        },
        goToPrevious() {
          this.$refs.flickity.previous()
        },
        onInit() {
          this.$refs.flickity.on('change', (event) => {
            this.selectedIndex = event
            console.log('current index', event)
          })
        },
      },
    }
    </script>
    
    <style>
    /* external css: flickity.css */
    
    * {
      -webkit-box-sizing: border-box;
      box-sizing: border-box;
    }
    
    .carousel-cell {
      width: 80%;
      min-height: 50vh;
      max-height: 80vh;
      object-fit: contain;
      margin-right: 10px;
    }
    </style>
    

    There was indeed no other event, which is super strange and I took the libery to write previous/next buttons rather than keep something manual but you could compute and offset (did not found any method for a direct setter).