timmack
timmack

Reputation: 590

How to access an element's ref index within the nested v-for loop in vue.js?

Is it possible to access an element within the nested v-for loop by using the refs index of the element? I mean, I'm trying to focus a textbox that is within the nested v-for loop which I used to access by its refs index. It works fine for a single v-for loop but not with nested.

For more details here's my loop structure:

This works

<div v-for="(comItem, index) in commentItems" :key="comItem.commentId">
 <textarea ref="addRep" ></textarea>
</div>
  this.$nextTick(() => {
                        this.$refs.addRep[index].focus()
                    });

This won't work

<div v-for="(cont, i) in contentItems" :key="cont.contentId">
    ...
     <div v-for="(comItem, index) in commentItems" :key="comItem.commentId">
     <textarea ref="addRep" ></textarea>
     </div>

</div>
  this.$nextTick(() => {
                        this.$refs.addRep[index].focus()
                    });
Or
 this.$nextTick(() => {
                        this.$refs.addRep[i].focus()
                    });

With the nested html v-for loop structure. The focus will just jump around anywhere. To anyone who encountered this kind of scenario. Please assist me if you know the solutions. Thanks.

Upvotes: 2

Views: 2855

Answers (1)

skirtle
skirtle

Reputation: 29102

Trying to calculate the appropriate index within addRep is a little tricky. You'd need the values of both i and index and then count up through the relevant arrays to work out the appropriate index.

A simpler way to do this is to use a dynamic ref name. We still need i and index to find the relevant element but there's no calculation required.

The core trick here is to set the ref to :ref="`addRep${i}`", or equivalently :ref="'addRep' + i" if you prefer. So you'll end up with multiple named refs, addRep0, addRep1, etc., each with its own array of elements. The value of i tells you the ref name and the index tells you the index within that array.

Here's an example:

new Vue({
  el: '#app',
  
  data () {
    return {
      contentItems: [
        {
          contentId: 1,
          comments: [
            {
              commentId: 1,
              text: 'A'
            }, {
              commentId: 2,
              text: 'B'
            }, {
              commentId: 3,
              text: 'C'
            }
          ]
        }, {
          contentId: 2,
          comments: [
            {
              commentId: 1,
              text: 'D'
            }
          ]
        }, {
          contentId: 3,
          comments: [
            {
              commentId: 1,
              text: 'E'
            }, {
              commentId: 2,
              text: 'F'
            }
          ]
        }
      ]
    }
  },
  
  methods: {
    onButtonClick (i, index) {
      this.$refs[`addRep${i}`][index].focus()
    }
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>

<div id="app">
  <div v-for="(cont, i) in contentItems" :key="cont.contentId">
    <h4>{{ cont.contentId }}</h4>
    <div v-for="(comItem, index) in cont.comments" :key="comItem.commentId">
      <textarea :ref="`addRep${i}`" v-model="comItem.text"></textarea>
      <button @click="onButtonClick(i, index)">Focus</button>
    </div>
  </div>
</div>

Upvotes: 4

Related Questions