How to use createAnimation properly in setup method?

Trying to do something like this:

<template>
  <ion-item button @click="onSelected">
    <ion-icon icon="caret-down-circle" ref="toggleIcon" />
  </ion-item>
<template>

...

setup() {

const toggleIcon = ref()

const toggleAnimation = createAnimation()
            .addElement(toggleIcon.value)
            .duration(500)
            .fromTo('opacity', '1', '0')

function onSelected() {
  toggleAnimation.play()
}

return {
  onSelected
}

}

I understand that this does not work because the toggleIcon template ref does not get bound until the component is mounted, so the animation does not get added to the element properly. What I am unsure about is how to arrange this properly so that the animation will get bound properly and be available within the onSelected method?

Tried creating the animation inside an onMounted method, but then it is unavailable when the onSelected method is defined. If I define the method inside onMounted as well, then it wont be available to return from the setup method initially.

The examples in docs don’t seem to provide enough context to clarify proper usage either. Appreciate any suggestions. Hopefully I am just missing some basic piece.

Can you try using the onMounted hook and see if that helps?

import { onMounted } from 'vue';

setup() {
  ...
  onMounted(() => {
    const toggleAnimation = createAnimation()
      .addElement(toggleIcon.value)
      .duration(500)
      .fromTo('opacity', '1', '0');
  });

}

When I tried that, the animation was not available to the onSelected method defined outside of onMounted. When I tried moving onSelected inside onMounted as well, then it was not defined when returned from the setup method. Seems like a catch 22.

You will probably need to do something like this:

let toggleAnimation;

onMounted(() => {
  toggleAnimation = createAnimation()
      .addElement(toggleIcon.value)
      .duration(500)
      .fromTo('opacity', '1', '0');
  });
}

const onSelected = () => {
  toggleAnimation && toggleAnimation.play();
}

This is not working either, but the immediate problem seems to be that the ref value is still undefined even within onMounted for some reason. Not sure why that is though, everything seems to be named properly.

Hard to say what the issue is without being able to reproduce it myself. Can you provide a link to a GitHub repo?

My teammate helped me finish the puzzle:

  1. Needed to return the toggleIcon ref from setup function and
  2. Needed to reference the $el property of the ref in addElement, ie .addElement(toggleIconRef.value.$el)

I can easily imagine other people will likely make the same mistakes when trying to work off the current samples in the docs page though. Not sure why they are not referring to the $el property as mentioned specifically there and whether that is a bug or just a different context than I am working with here maybe.

Appreciate the feedback!

Glad it’s fixed! Regarding the $el usage, this is because a ref will give you a reference to the IonIcon Vue Component, but what createAnimation wants is an actual DOM Element. Using $el gets you a reference to the DOM Element.

This is mentioned in our docs here: https://ionicframework.com/docs/vue/quickstart#calling-methods-on-components

Thanks Liam, that makes sense. Shouldn’t the Vue animation samples be referencing the $el this way also though? They do not currently: https://ionicframework.com/docs/utilities/animations

Best wishes

Not necessarily. If you have the following:

<div ref="helloRef">Hello World</div>

Then helloRef.value will give you the actual div element.

If you are using Ionic components, then you need to do helloRef.value.$el because helloRef.value is the Vue component. Ideally we would just forward your ref to the underlying Web Component, which is something we do in Ionic React. Unfortunately Vue does not support forwarding refs at the moment, so we cannot do that here.

edit: We are looking into requesting a ref forwarding feature in Vue 3 since it is a bit confusing to have to use $el on the Ionic components.

1 Like

I see, that makes sense now. Thanks for clarifying and exploring a more optimal potential solution! :crossed_fingers:

Cheers

1 Like