2

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.

9
  • When you say it 'won't work', could you be more specific? What does happen? Within the $nextTick callback where are you getting the values for index and i? Have you tried logging the value of this.$refs.addRep within that callback to see whether the array exists and what is in it? Is the problem simply trying to calculate the appropriate array index within a nested loop? Commented Nov 5, 2019 at 3:53
  • I did all the loggings for getting the values of each indexes. What happens is if it's in the nested html structure with v-for loops the focus is not consistent anymore. It will just jump around anywhere. Commented Nov 5, 2019 at 3:59
  • @skirtle I think the problem is simply trying to calculate the appropriate array index within a nested loop. Commented Nov 5, 2019 at 4:03
  • 1. Should :key="contItem.commentId" be :key="comItem.commentId"? I don't see contItem defined anywhere. 2. Is there a link between the outer and inner loop? As presented in the question the inner loop is just churning out the same list of commentItems for each cont item. I would expect it to be something like v-for="(comItem, index) in cont.commentItems". I know this sounds like an unimportant detail but it makes a huge difference to how to calculate the appropriate index. Commented Nov 5, 2019 at 4:14
  • Yes, that was a typo error it was <div v-for="(comItem, index) in commentItems" :key="comItem.commentId"> Commented Nov 5, 2019 at 4:19

1 Answer 1

4

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>

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.