How do you use Gestures API in a Vue Component?

I’m probably missing something obvious, but I don’t understand how to integrate the Vue Gestures double press API example in the Ionic documentation into a Vue component. The example in the Ionic docs seems to be lacking any Component context and my attempts to integrate either inline after the tag or in a setup() or created() method all produce an event registration error.

Uncaught (in promise) TypeError: Cannot read property '__zone_symbol__addEventListener' of null

Where should I be declaring gestures?

Here is an example that produces the error:

DoublePressDemo.vue

<template>
  <ion-content class="ion-padding-top">
    <div class="rectangle">
      Double click me to change the color
    </div>
  </ion-content>
</template>

<script>
import {IonContent} from '@ionic/vue';
import {createGesture} from '@ionic/vue';
export default {
  name: "DoublePressDemo",
  components: {IonContent},
  created() {
    const backgrounds = ['rgba(0, 0, 255, 0.5)', 'rgba(0, 255, 0.5)', 'rgba(255, 0, 0, 0.5)', 'rgba(255, 255, 0, 0.5)', 'rgba(255, 0, 255, 0.5)', 'rgba(0, 255, 255, 0.5)'];
    const DOUBLE_CLICK_THRESHOLD = 500;
    const rectangle = document.querySelector('.rectangle');
    const gesture = createGesture({
      el: rectangle,
      threshold: 0,
      onStart: () => {
        onStart();
      }
    });

    gesture.enable(true);

    let lastOnStart = 0;
    let currentColor = 'rgba(0, 0, 255, 0.5)';

    const onStart = () => {
      const now = Date.now();
      if (Math.abs(now - lastOnStart) <= DOUBLE_CLICK_THRESHOLD) {
        rectangle.style.setProperty('background', getRandomBackground());
        lastOnStart = 0;
      } else {
        lastOnStart = now;
      }
    }

    const getRandomBackground = () => {
      const options = backgrounds.filter(bg => bg !== currentColor);
      currentColor = options[Math.floor(Math.random() * options.length)];

      return currentColor;
    }
  }
}
</script>

<style scoped>
.rectangle {
  width: 100%;
  max-width: 500px;
  height: 100px;
  background-color: rgba(0, 0, 255, 0.5);
  text-align: center;
  line-height: 100px;
  user-select: none;
}
</style>

Is rectangle defined? createGesture will not work if you pass null to el.

The line const rectangle = document.querySelector('.rectangle'); selects it on my div, but you are right, it is null. I changed it to ionViewDidEnter() and no error. I got my life cycle hooks mixed up.

Any recommendation for a better place to declare gestures than ionViewDidEnter()?

You can use the mounted lifecycle hook if you want to set your gesture up as soon as
possible:

onMounted Composition API: Composition API | Vue.js
mounted Options Hook: Lifecycle hooks | Vue.js

1 Like

@ldebeasi hi! Although I get no error, the onStart or onEnd handlers do not fire. I copied the example directly from Ionic docs, so I am wondering what else I am doing wrong?

O, it has to be in onMounted() otherwise it doesn’t work. All good now. Thanks!

One last question: would you happen to know how I bind my Vue methods: {} functions to the gesture? I need it to interact with the Vue component but the handlers in the Gesture API example are all isolated inside the setup() function.

If you use the mounted() lifecycle option, you should have access to your methods. You may need to setup the gesture in this.$nextTick in order to ensure all child components have been rendered. See Lifecycle hooks | Vue.js for an example

1 Like