Vue: v-ref inside v-for is not defined

Created on 17 Dec 2015  路  15Comments  路  Source: vuejs/vue

When using v-ref on a component with v-for it produces a list of components.
But, when using components inside a v-for and using v-ref on this component, I expect the same behavior but the component list is not present in $refs.

See this code sample illustrating the issue with Vue.js 1.0.11: https://jsfiddle.net/noirbizarre/jms2gzpt

I think this is related to #1850 and to #1697

discussion

Most helpful comment

@yyx990803 I have the same problem. And I think you should let developers decide how to name for v-ref. Developer will solve the conflict of v-ref name. Let's see below code.
Situation 1:

<div v-for="item in items">
  <comp v-ref:nested{{item}} :value="item"></comp>
</div>

We can use $refs.nested{{index}} to name them.

Situation 2:

<div v-for="item in items">
  <div v-for="sub in item.subs">
    <comp v-ref:nested{{item.sub}}></comp>
  </div>
</div>

What we need to do is add a feature to make v-ref accept variable.
How about that?

All 15 comments

This is currently intended behavior: refs are only defined in the v-for scope it is in.
I'm not sure it it makes sense to define the refs on the surrounding component - it could lead to some pretty tricky cases:

<div v-for="item in items">
  <comp v-ref:nested :value="item"></comp>
  {{ $refs.nested }} <!-- should this be a single component, or an array? -->
</div>

And with nested v-fors:

<div v-for="item in items">
  <div v-for="sub in item.subs">
    <comp v-ref:nested></comp>
  </div>
</div>

What should $refs.nested be in this case? A nested array? That doesn't really sound that useful.

Closing since it doesn't seem to be a common use case (lack of discussion).

@yyx990803 I have the same problem. And I think you should let developers decide how to name for v-ref. Developer will solve the conflict of v-ref name. Let's see below code.
Situation 1:

<div v-for="item in items">
  <comp v-ref:nested{{item}} :value="item"></comp>
</div>

We can use $refs.nested{{index}} to name them.

Situation 2:

<div v-for="item in items">
  <div v-for="sub in item.subs">
    <comp v-ref:nested{{item.sub}}></comp>
  </div>
</div>

What we need to do is add a feature to make v-ref accept variable.
How about that?

@yyx990803 Couldn't you see me here?

I'm also having the same problem. Is there posible to have some syntax like what @zyf0330 proposed? or are there any workaround to get a specific component inside a v-for loop?

@YerkoPalma if you can ensure only one kind of component inside a v-for, then you can use $children. Or you can use css selector with $el as the base element.

finally I agree with @yyx990803
I case of $els, it can become very complex to understand. I rethinked my solution to avoid that.

I agree with @zyf0330. Dynamic v-ref's could be really useful. For example, if you have multiple instances of a component and you want to track one down and call a method on it, a unique id can be assigned to each component as a required prop, which can then be used by the consumer to easily fetch it, without having to hunt it down the tree.

E.g, i've built a pagination component which accepts a 'for' prop:

  <pagination for="table2" per-page="25" records="100"></pagination>

would be nice if the consumer could do something like

this.$refs.table2.setPage(1)

Sorry, but I don't see your example is related with what i said.
@matfish2

Well, I probably misunderstood... Sorry about that

@noirbizarre How did your resolve this in the end.

@FrankFang did you manage to fix this already? I have the exact same problem..

@MrPhilipT I use

this.$el.querySelector(`[name="whatever-${index}"]`)

;)

@FrankFang okay, I was able to resolve my issue using v-model in the selector instead of v-ref, so for instance <selector v-model="something"><option v-for="option in options">{{ option }} </option></selector> and putting something:"", in data, turns out I didn't really need v-ref..

As an example, this is how I worked around the problem:

<tr v-for="contract in contracts" :key="contract.id">
   <td>
        <button @click="showModal(contract)">Edit</button>

        <contract-modal :contract="contract" ref="modals"></contract-modal>

[...]

    showModal(contract) {
        this.$refs.modals.find(ref => ref.contract.id === contract.id).show = true;
    },


Note that the component ContractModal in this example has a boolean property show, which controls the visibility of the modal. The essence of this example is the call to this.$refs.modals.find() that fetches the component from the array.

Was this page helpful?
0 / 5 - 0 ratings