LJP
LJP

Reputation: 1951

How to add dynamic ref in vue.js?

I have some dynamic <input> elements in my dom rendered from for loop in vue. I need to add ref property to each of them by appending an Id to each ref like element1,element2,..etc. How to do this in vue?

<div v-for="(result, index) in data" :key="index">
    <input type="text" type="file" ref="element" />
</div>

How to add ref if result.id exists

Upvotes: 106

Views: 157204

Answers (4)

phlaxyr
phlaxyr

Reputation: 1125

Update for Vue 3.2.47+: if specifically you need to access elements of a v-for, you can attach a ref to an array directly: (docs). Example code

<script setup>
// ...
const itemRefs = ref([]);
</script>

<template>
  <Comp v-for="item in list" ref="itemRefs">
    {{ item }}
    {{ itemRefs[2] }}
  </Comp>
<template>

If your v-for is a list of custom components, be sure to expose any fields or functions you need with defineExpose.

If furthermore you require that the list of refs maintain the same order, I found this answer to be very helpful.

Upvotes: 8

choasia
choasia

Reputation: 10852

Simply use v-bind like :ref="'element' + result.id" or ref="`element${result.id}`".

Check fiddle here.

new Vue({
  el: '#app',
  data: {
    data: [{id: 1}, {id: 2}, {id: 3}],
  },
  mounted() {
    console.log(this.$refs);
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>

<div id="app">
<div v-for="(result, index) in data" :key="index">
    <input type="text" type="file" :ref="'element' + result.id" />
</div>
</div>

Edited: Thanks to Vamsi's edit, I replaced index with result.id
Edited 8/28: Thanks to grokpot, I added a sample powered by Template literals.

Upvotes: 129

Roland
Roland

Reputation: 27729

Using v-bind:ref or just :ref.

Follow below a simple example including how to access a dynamic ref

<template>
    <div>
        <div class="inputs" v-for="input in inputs" :key="input.id">
            <input type="text" v-model="input.name" :ref="'name' + input.id">
            <button @click="displayRef('name' + input.id)">
                 Click to see the input ref
            </button>
            <hr>
            <button @click="displayAllRefs">Click to see all refs</button>
        </div>
    </div>
</template>

And the script:

<script>
    export default {
        data() {
            return {
                inputs: [
                    { id: Date.now(), name: '', lastName: '' }
                ]
            }
        },
        methods: {
            displayRef(ref) {
                console.log(this.$refs[ref]) // <= accessing the dynamic ref
                console.log('The value of input is:',this.$refs[ref][0].value) //<= outpouting value of input
            },
            displayAllRefs() {
                console.log(this.$refs)
            }
        }
    }
</script>

Upvotes: 51

You have dynamic refs and have multiple elements. To target any single node just pass the index within method params

     new Vue({
      el: '#app',
      data: {
        data: [{id: 1}, {id: 2}, {id: 3}],
      },
       methods: {
      addNewClass(index) {
      
      this.$refs.element[index].classList.add('custom-class')
    }
  },
    
    })
<script src="https://npmcdn.com/vue/dist/vue.js"></script>

     
<div id="app">
  <div v-for="(result, index) in data" :key="index">
   <div ref='element' @click='addNewClass(index)' class='custom-container'>
        
   </div>
</div>

Upvotes: 23

Related Questions