Encountered a problem while integrating Flickity Events with Vue3 and TypeScript: receiving an error stating that "this$refs.flickity.on

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;
}

Answer №1

this.$refs.flickity refers to the Flickity.vue component, not the actual flickity instance. The lack of an on() method in your Flickity.vue component is causing the error you are seeing.

To solve this, you can expose the flickity instance's on() method by creating a component method in your Flickity.vue file:

// Flickity.vue
export default defineComponent({
  setup() {
    return {
      on(eventName: string, listener: () => void) {
        flickity?.on(eventName, listener)
      }
    }
  }
})

Don't forget to update the type declaration to include the on() method:

// flickity.d.ts
interface IFlickity {
    //...
    on(eventName: string, listener: () => void)
}

declare module 'flickity' {
    const Flickity: IFlickity;
    export = Flickity;
}

Check out the demo for more information.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing jQuery for easy drag-and-drop functionality in web development

I have two lists which are currently using jQuery for functionality. An example can be found here. I need the same basic functionality but with some modifications: Instead of just getting all sortable items by clicking "Get items," I want to be able to dr ...

JavaScript and TypeScript: Best practice for maintaining an Error's origin

Coming from a Java developer background, I am relatively new to JavaScript/TypeScript. Is there a standard approach for handling and preserving the cause of an Error in JavaScript/TypeScript? I aim to obtain a comprehensive stack trace when wrapping an E ...

executing functions that return a JSX component within the render method

In an effort to enhance readability, I am striving to condense the length of the render() method by utilizing class methods that contain isolated JSX elements. A snag arises when attempting to apply this technique to more than one JSX element. Despite en ...

I've encountered difficulty displaying images while utilizing Vuetify in my projects

I'm having trouble getting icons to display on my navigation drawer. <v-list-item-icon> <v-icon left small>email</v-icon> </v-list-item-icon> I used the email icon provided by Vuetify. I also tried to display an image i ...

Design a table within an mdDialog that allows for editing of data presented in JSON format

I'm attempting to implement a dialog using JSON data. $scope.showAttributeData = function(data) { $scope.feature = data console.log($scope.feature) var that = this; var useFullScreen = ($mdMedia('sm') ...

Tips for utilizing formidable with NextJS 13 API for image uploading and resolving request errors

I've been working on integrating image uploading functionality into my application. I'm currently using NextJS version 13.4.4 along with formidable@v3. However, whenever I attempt to upload an image, I encounter the following error: error TypeE ...

Sending a JSON object as a map through AJAX to an MVC controller

I am looking to send a map (dictionary) to the MVC controller along with a string parameter. var reportName= 'ReportName'; var FilterValues = new Map([ [0, "value1"], [1, "value2"], [2, "value3"], ]); var model = { reportName: reportName, ...

Retrieve information for AJAX tooltip from a specific URL

I am currently utilizing a script for tooltips. Is there a method available to dynamically load the content of a tooltip from a URL (using dynamic content loaded from a PHP script) rather than specifying the path to an html/php file? For Example What I ...

The Select element in angular fails to choose the intended option when tested with Cypress

I am encountering a challenge in my automation testing project where I need to select an option from a select element. The project is built using Angular and I am using Cypress for automation testing. As a newcomer to Cypress, I followed the instructions ...

Concealing Vue object properties

Is it feasible to indicate specific object properties that should not be displayed? This can come in handy for debugging purposes, especially when dealing with large objects or objects that create a loop. For instance, let's say we have an object: c ...

What is the proper way to specifically define a new property on the `global` object in TypeScript?

I want to define a type signature for the variable below: (global as any).State = { variables: {}, }; How can I declare the type of State? If I try (global as any).State: Something = ..., the compiler displays an error message saying ; expected. It se ...

Managing timestamps of creation and modification with Sequelize and Postgresql

As a newcomer to Sequelize, I find myself grappling with the intricacies of model timestamps management. Despite prior experience with another ORM in a different language, I'm struggling to wrap my head around how to automatically handle "createdAt" a ...

Unable to locate the main source for loading

I am facing an issue with my app where I am unable to load a basic component. It seems like a simple problem, but I just can't seem to figure it out. Here is the code for my component: import { Component, OnInit } from '@angular/core'; imp ...

Invent a customizable receptacle for component

I am working on a component and I want to be able to change the tag name of the container for that component, like this: <my-component tagName="section"></my-component> so that it renders like this: <section>... my inner component tags ...

Determining height of an element in AngularJS directive prior to rendering the view

As I dive into the world of Angular, any assistance is greatly welcomed. My goal is to vertically align a div based on screen size (excluding the header and footer) when the page loads, the window resizes, and during a custom event triggered by the user ex ...

How to access an element from the JSON return value retrieved from an AJAX call using JavaScript

After making an ajax call that returns successfully, I am facing a problem. I cannot access individual elements of the array it returns, and therefore unable to console log it. The error message indicates that the track is not defined, even though it is pr ...

Import components on the fly

In my Home.vue component, I am attempting to dynamically import components. The Vue component structure is as follows: <template> <div> <!-- NEW --> <div v-for="widget in widgets"> <component v-b ...

Achieving the perfect sorting result in an array using Javascript

I am attempting to arrange the objects inside an array below in ascending order by their values and achieve the desired output as shown: var arr = [{"DOA Qty":"0.000665921017598927382910198160","LOS%":"0","FID Valid EC By Part":"0.004186044328301671376196 ...

Utilizing FCKEditor to incorporate dimensions of width and height into image elements

I'm currently facing an issue while attempting to specify width and height for images within an old WYSIWYG FCKEditor. The challenge arises when trying to retrieve the naturalWidth/naturalHeight properties, as they return values of 0. What could I be ...

Angular Appreciation Meter

Looking to create a rating system using Angular. The square should turn green if there are more likes than dislikes, and red vice versa (check out the stackblitz link for reference). Check it out here: View demo I've tried debugging my code with con ...