[SOLVED] This.$refs.key returns undefined when it really is

Hello.
I have a problem exactly the same as defined here although this one is archived.

I am using Vue 2.0 with Webpack. When I say console.log(this.$refs) (inside created() method inside a low level component) it returns:

▼ Object {}
    ▶ b254c249a585740ef79c26e71a8739ac: a.envelope
    ▶ __proto__: Object

, but when I say console.log(this.$refs.b254c249a585740ef79c26e71a8739ac) I get undefined.

1 Like

If you look at the lifecycle digramm you can see that when the created() hook is called, the component’s template/render function has not been compiled.

That’s why at this moment, this.$refs.someName is undefined - the referenced component simply hasn’t been created yet.

When you log the $refs object, it will also not contain this component at this very moment - but since the program will continue to run, the component will be added to the object immediately afterwards, when the content is rendered - that’s why you can see it in the console.

Try adding a breakpoint after the console.log() and you will be able to see that $refs has not been populated with any referenced components yet.

6 Likes

Thank you for this extensive explanation. Could you explain what is a use-case or how is the $refs object useful then? :slight_smile:

@DCzajkowski $refs contains registered children of the current component, allowing you to, for instance, access their methods/properties directly.

<child-component ref="childComponentA"></child-component>
<a @click.prevent="triggerChildMethod">Trigger A's method</a>
methods: {
  triggerChildMethod() {
    this.$refs.childComponentA.childMethod()
  }
}

Personally, I find myself using ref on non-components sometimes, for the sake of convenience :slight_smile:

<div tabindex="-1" ref="focusableDiv"></div>
<a @click.prevent="setFocus">Focus</a>
methods: {
  setFocus() {
    // I can access the DOM object directly here without any query.
    this.$refs.focusableDiv.focus()
  }
}
1 Like

Ok. That makes sense. It would be cool though if you could interact with the DOM on (or just after) initial render using the ref, but it makes sense, I guess.

Thanks guys :slight_smile:

Well, you can. in mounted(), $refs has those components ready for you.

Look at the lifecycle diagramm again :wink:

4 Likes

The lifecycle diagram helped a lot. Thanks!

Hi. I am trying to access $refs inside mounted() and I am getting a weird scenario. When I console.log $refs, I can see the $refs object and the ref I am looking for.
However when I console.log $refs.myRef, undefined is printed.
Am I doing something wrong?

 mounted() {
    console.log('*mounted', this.$refs); // I can see myRef inside the $refs object in the console
    console.log('*mounted', this.$refs.myRef); // prints undefined
    console.log(this.$refs.myRef[0]); // Error: Cannot read property '0' of undefined
  },
2 Likes

Just read my explanations in this thread, especially this comment: [SOLVED] This.$refs.key returns undefined when it really is

I explain just what you experience.

But @matan188 is using it inside mounted(), not created(), so it should be available, no?

That depends, I don’t know anything about his component. maybe he has a v-if on the component that only resolves to true after some data has been loaded asynchronously.

That would result in the same effect. Other things are possible as well.

8 Likes

Thanks for the quick reply!
That’s exactly what’s happening! I am loading some data asynchronously in the beforeMount() hook and didn’t realize it could affect the mount() logic. However, I do find it quite odd that I can see the myRef object when I print $refs to the console, I guess that has to do with the thread you referred me to. Anyway thanks a lot!
Now I just have to figure out how to reach that ref… I want to add an event listener to an element that is contained inside that ref component. The ref is on a Bootstrap element, so I cannot access its child directly.
Is there a good way for doing this?

1 Like

I figured it out!
It is possible to add native events to Bootstrap inputs by using the native modifier so no need to use addEventListener.
i.e: <b-form-input @focus.native="myFunction" />

According to what you said. We cannot get $refs in created is because render function is not yet compiled. And refer to the lift cycle diagram. $refs should be ready in beforeMount state. However. I can only get $refs content in mounted state. :frowning:

Oh my God! You are right, boy!

when v-if in component child modify to show, the lifecycle call again…

nice info.

same problem

If someone needs help, wrapping the this.$refs in this.$nextTick` will wait for the code render.

this.$nextTick(() => {
    normalizeArray(this.$refs.form).classList.remove("was-validated");
});

I’ve read all but I have a similar problem:

<div v-if="step==1">
    <button @click="setName">Set Name</button>
</div>

<div v-if="step==2">
    <input type="text" id="userName" ref="userName" v-model="item.name"/>
</div>

In the methods:

setName() {
    this.step = 2;
    Vue.nextTick(() => {
        console.log(this.$refs);
        console.log(this.$refs.userName);
    });
},

When I click the button I get:
userName: input#userName (for the first console log)
undefined (for the second console log)