I have successfully implemented a custom Flickity.vue object for Vue 3 with TypeScript support, based on the solution provided here.
However, when attempting to listen for events on my flickity
carousel, I encounter runtime type errors in the console:
this$refs.flickity.on is not a function
What is causing this issue in my current method?
DisplayPage.vue
<template>
<div class="row">
<div class="col d-block m-auto">
<flickity ref="flickity" @init="onInit" :options="flickityOptions">
</flickity>
</div>
</div>
</template>
<script lang="ts">
import {defineComponent} from "vue";
import Flickity from "./widgets/Flickity.vue";
export default defineComponent({
components: {
Flickity
},
data() {
return {
flickityOptions: {
initialIndex: 1,
prevNextButtons: true,
pageDots: true,
wrapAround: false,
}
};
},
methods: {
configureBankAccountCarousel() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(this.$refs.flickity as any).append(this.makeFlickityCell())
},
makeFlickityCell() {
const cell = document.createElement('div')
cell.className = 'carousel-cell'
cell.textContent = "Bank Acct"
}
},
mounted() {
this.configureBankAccountCarousel();
this.configureBankAccountCarousel();
this.$nextTick(() => {
// EVENTS
(this.$refs.flickity as any).on('ready', function () { //Type ERROR here
console.log('Flickity is ready!')
})
})
},
});
</script>
Flickity.vue
<template>
<div ref="root" class="flickity">
<slot />
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, onUnmounted, ref } from 'vue'
import Flickity from 'flickity'
export default defineComponent({
props: {
options: Object,
},
setup(props) {
let flickity: typeof Flickity | null = null
const root = ref<HTMLElement | null>(null)
onMounted(() => flickity = new Flickity(root.value as HTMLElement, props.options))
onUnmounted(() => flickity?.destroy())
return {
root,
append(element: HTMLElement) {
flickity?.append(element);
flickity?.select(-1)
}
}
},
})
</script>
<style scoped>
@import '~flickity/dist/flickity.css';
.flickity .carousel {
background: #EEE;
margin-bottom: 40px;
}
.flickity::v-deep .carousel-cell {
height: 200px;
width: 25%;
margin: 0 10px;
background: #6C6;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8px;
}
.carousel-cell {
background-color: #248742;
width: 300px; /* full width */
height: 160px; /* height of carousel */
margin-right: 10px;
}
/* position dots in carousel */
.flickity-page-dots {
bottom: 0px;
}
/* white circles */
.flickity-page-dots .dot {
width: 12px;
height: 12px;
opacity: 1;
background: white;
border: 2px solid white;
}
/* fill-in selected dot */
.sr-flickity-page-dots .dot.is-selected {
background: white;
}
/* no circle */
.flickity-button {
background: transparent;
}
/* big previous & next buttons */
.flickity-prev-next-button {
width: 100px;
height: 100px;
}
/* icon color */
.flickity-button-icon {
fill: white;
}
/* hide disabled button */
.flickity-button:disabled {
display: none;
}
</style>
flickity.d.ts
interface IFlickity {
new (el: string | HTMLElement, options?: Record<string, unknown>): this;
append(element: HTMLElement);
destroy();
select(id: string | number);
}
declare module 'flickity' {
const Flickity: IFlickity;
export = Flickity;
}