I have a component template that looks like this:
<div v-for="thing of someListOfObject">
<div :ref="thing.id">
hi !
</div>
</div>
To access a ref in the script, you should normally do :
<template>
<div ref="test" />
</template>
<script setup>
const test = ref(null)
</script>
The name of the const should be the same name as the ref. But, as my ref is declared from a property, I couldn’t find a way to access it from my script.
I already tried to access child from parents ref like that :
<template>
<div v-for="thing of someListOfObject" ref="things">
<div>
hi !
</div>
</div>
</template>
<script>
const things = ref([])
</script>
And it kinda worked, but in my case, the child element is nested in a bunch of other div so access it from the parent is a real mess.
Any ideas how directly access the nested ref?
2
According to your first snippet you want to fill id
prop of the list with DIV references. You can do this with a directive:
Playground
<script setup>
import { ref , reactive} from 'vue'
const someListOfObject = reactive(Array.from({length: 10}, ()=>({})));
const vMount = {
mounted($el, {value: idx}){
someListOfObject[idx].id = $el;
}
}
</script>
<template>
<div>{{someListOfObject}}</div>
<div v-for="(thing, idx) in someListOfObject">
<div v-mount="idx">
hi !
</div>
</div>
</template>
Although @Nicolas found the answer to their question, I’ll leave a more detailed explanation and clarification here. The documentation he referenced provides a partial answer to the question. The code he wrote is unclear and does not align with the guidelines provided in the documentation.
Vue 3.5 or above (new)
Starting from Vue 3.5, a special ref called templateRef has been introduced. To use it effectively, it is recommended to review the example in the documentation.
When
ref
is used insidev-for
, the corresponding ref should contain an Array value, which will be populated with the elements after mount:<code><script setup>import { ref, useTemplateRef, onMounted } from 'vue'const list = ref([/* ... */])// Declare array for the dynamic collection of refs// CHANGED: The variable name can differ from the value of the Template element's ref attribute. ---> in my example itemRefs custom-name related to ref="items"const itemRefs = useTemplateRef('items')onMounted(() => console.log(itemRefs.value))</script><template><ul><li v-for="item in list" ref="items">{{ item }}</li></ul></template></code><code><script setup> import { ref, useTemplateRef, onMounted } from 'vue' const list = ref([ /* ... */ ]) // Declare array for the dynamic collection of refs // CHANGED: The variable name can differ from the value of the Template element's ref attribute. ---> in my example itemRefs custom-name related to ref="items" const itemRefs = useTemplateRef('items') onMounted(() => console.log(itemRefs.value)) </script> <template> <ul> <li v-for="item in list" ref="items"> {{ item }} </li> </ul> </template> </code><script setup> import { ref, useTemplateRef, onMounted } from 'vue' const list = ref([ /* ... */ ]) // Declare array for the dynamic collection of refs // CHANGED: The variable name can differ from the value of the Template element's ref attribute. ---> in my example itemRefs custom-name related to ref="items" const itemRefs = useTemplateRef('items') onMounted(() => console.log(itemRefs.value)) </script> <template> <ul> <li v-for="item in list" ref="items"> {{ item }} </li> </ul> </template>
Source: Refs inside
v-for
This way, you can dynamically create an array of refs.
In the past, a reactive reference to a Template element could be made with the ref(null)
declaration. Previously, there was a strict rule that the name of the declared ref variable had to match the string in the Template element’s ref attribute. From now on, with useTemplateRef('ref-attribute-value')
, the variable name is no longer bound by this constraint.
Similarly, to create a dynamic ref array in the past, you had to declare an empty array ref with a strict variable name. Now, you can simply use useTemplateRef
paired with v-for
.
Use dynamically Template ref-attribute value
The value passed to useTemplateRef can also be dynamic:
<script setup>
import { useTemplateRef} from 'vue'
const dynamicName = "inputDynamicRefName"
const input = useTemplateRef(dynamicName)
</script>
<template>
<div>
<input :ref="dynamicName" />
</div>
</template>
- Accessing the Refs alias
useTemplateRef
(refer to single Template element) – Vue Docs - Refs inside
v-for
(refer to multiple Template elements byv-for
) – Vue Docs
Usage before 3.5 (old)
Previously, you had to declare an empty array of refs, which, when injected alongside a v-for
, achieved a similar result.
<code><script setup>import { ref, useTemplateRef, onMounted } from 'vue'const list = ref([/* ... */])// Declare array for the dynamic collection of refs// IMPORTANT: The variable name must strictly match the value of the Template element's ref attribute! ---> itemRefsconst itemRefs = ref([]) // from 3.5 can use useTemplateRef()onMounted(() => console.log(itemRefs.value))</script><template><ul><li v-for="item in list" ref="itemRefs">{{ item }}</li></ul></template></code><code><script setup> import { ref, useTemplateRef, onMounted } from 'vue' const list = ref([ /* ... */ ]) // Declare array for the dynamic collection of refs // IMPORTANT: The variable name must strictly match the value of the Template element's ref attribute! ---> itemRefs const itemRefs = ref([]) // from 3.5 can use useTemplateRef() onMounted(() => console.log(itemRefs.value)) </script> <template> <ul> <li v-for="item in list" ref="itemRefs"> {{ item }} </li> </ul> </template> </code><script setup> import { ref, useTemplateRef, onMounted } from 'vue' const list = ref([ /* ... */ ]) // Declare array for the dynamic collection of refs // IMPORTANT: The variable name must strictly match the value of the Template element's ref attribute! ---> itemRefs const itemRefs = ref([]) // from 3.5 can use useTemplateRef() onMounted(() => console.log(itemRefs.value)) </script> <template> <ul> <li v-for="item in list" ref="itemRefs"> {{ item }} </li> </ul> </template>
Source: Refs inside
v-for
Use dynamically Template ref-attribute value
Essentially, after creating an object, we can add the element obtained through the ref attribute
as a property of that object.
<script setup>
import { reactive } from 'vue'
const dynamicName = "inputDynamicRefName"
const inputs = reactive({})
// It has nothing to do with the new useTemplateRef; I named it similarly only because of the similar functionality
const setTemplateRef = (key, el) => {
inputs[key] = el
}
</script>
<template>
<div>
<input :ref="(el) => setTemplateRef(dynamicName, el)" />
</div>
</template>
<script setup>
import { reactive, onMounted } from 'vue'
const things = reactive({})
const setTemplateRef = (id, el) => {
things[id] = el
}
onMounted(() => {
console.log(things.value)
})
</script>
<template>
<div v-for="(thing, index) in someListOfObject" :key="thing.id">
<div :ref="(el) => setTemplateRef(thing.id, el)">
hi!
</div>
</div>
</template>
- Function Refs alias
:ref="(el) => ..."
(refer to single Template element by ref function)
The solution is to use useTemplateRef:
<template>
<div v-for="thing of someListOfObject" ref="things">
<div>
hi !
</div>
</div>
</template>
<script setup>
import { useTemplateRef, onMounted } from 'vue'
for(thing in someListOfObject){
console.log(useTemplateRef(thing.id))
}
</script>
2