user2115620
user2115620

Reputation: 111

Vue2 + composition API - dynamic template refs

I am using Quasar (quasar.dev) with Vue2 + Composition API and am trying to access DOM elements with dynamically generated 'v-bind:ref' properties, following this page of the Vue3 docs:

https://v3.vuejs.org/guide/composition-api-template-refs.html#usage-inside-v-for

This is a codesandbox simplified representation of the issue: https://codesandbox.io/s/suspicious-pine-90qgd?file=/src/components/MyOuterComponent.ts

My component template (MyOuterComponent.vue):

<template>
  <div>
    <my-component
      v-for="(item, i) in list"
      v-bind:ref="
        (el) => {
          if (el) divs[i] = el
        }
      "
      v-bind:key="i"
    >
      {{ item }}
    </my-component>
  </div>
</template>

<script src='./MyOuterComponent.ts' />

and my script for that component:

import MyComponent from './MyComponent.vue'
import TMyComponent from './MyComponent'
import {
  defineComponent,
  onMounted,
  ref,
  reactive,
  onBeforeUpdate
} from '@vue/composition-api'
export default defineComponent({
  name: 'MyOuterComponent',
  components: { MyComponent },
  props: {},
  setup(props, context) {
    const list = reactive([1, 2, 3, 4, 5])
    const divs = ref<InstanceType<typeof TMyComponent>[]>([])

    // make sure to reset the refs before each update
    onBeforeUpdate(() => {
      divs.value = []
    })

    onMounted(() => {
      context.root.$nextTick(() => {
        console.log('THE COMPONENTs', divs, context.root.$refs)
        divs.value.forEach((div) => {
          console.log('My Div Ref: ', div)
        })
      })
    })
    return {
      list,
      divs
    }
  }
})

As seen in the docs I am expecting divs to be populated with the template refs for my dynamically generated components, which is what this line in my template should do:

v-bind:ref="(el) => { if (el) divs[i] = el }"

divs remains empty even when logged after nextTick. I expect to see 5 items referencing DOM elements in there.

If I change the template to:

<template>
  <div>
    <my-component
      v-for="(item, i) in list"
      v-bind:ref="item"
      v-bind:key="i"
    >
      {{ item }}
    </my-component>
  </div>
</template>

<script src='./MyOuterComponent.ts' />

I see the refs in context.refs but am told this property will be removed in Vue3 ;-(

Can somebody please tell me where I am going wrong? Thanks.

Upvotes: 2

Views: 8579

Answers (3)

Steven Spungin
Steven Spungin

Reputation: 29071

Although not supported as of now, you can still get to the old $refs as a workaround. This is not in Vue3, but will you by until it is implemented.

  <div v-for='i of 10' :key='i' ref='myRefs' />
setup(props, {refs}){
  // Workaround until Vue2 Composition API supports dynamic template refs.
  onMounted(()=>{
     myRefs = refs.myRefs // array of 10 refs
  })
}

Upvotes: 0

Jogiter
Jogiter

Reputation: 106

Firstly you need to import ref:

import { ref } from "@vue/composition-api"

A simple way is to add a ref to the list. You can reference the required ref using the list index.

<template>
  <div>
    <my-component
      ref="mycomponentRef"
      v-for="(item, index) in list"
      v-bind:key="index"
    >
      {{ item }}
    </my-component>
  </div>
</template>

<script>
export defineComponent({
  setup() {
    // this is an array, [ref0, ref1, ...]
    const mycomponentRef = ref()

    return { mycomponentRef }
  }
})
</script>

Upvotes: 2

user3657624
user3657624

Reputation: 31

It looks that vue-composition-api (vue2) doesn't support the :ref syntax. Take a look at https://github.com/vuejs/composition-api#limitations

A warning should be very helpful there.

Upvotes: 3

Related Questions