Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue - access nested childs using ref

Tags:

I have vue component which I use inside himself - data can have array with subelements and I use this array to render them in loop, and next level, next level etc. according to nesting level.

Now I would like to run child method from parent and then - if statements are ok, also call it to child, next level etc.

I use

    <mycomponent             ref="myFirstLevelRefName"             (...)     ></mycomponent> 

and then:

this.$refs.myFirstLevelRefName  

to call first-level childs. But what about about child nodes? I use them in view in that way:

    <mycomponent             v-for="(subElement, index) in getSubelements()"             ref="???"             v-bind:data="subElement"             v-bind:key="index"     ></mycomponent> 

I tried sent this.$refs from child level to console, but it's empty.

How should I set ref name in nested elements and then call them from parent?

like image 679
lukasamd Avatar asked Apr 05 '18 15:04

lukasamd


People also ask

How do you access child components at Vue?

To access child component's data from parent with Vue. js, we can assign a ref to the child component. And then we can access the child component data as a property of the ref. to assign the markdown ref to the markdown component.

How do you use refs at Vue?

Referencing DOM Elements in Vue # Vue can store references to DOM elements in a property called $ref . The first thing we have to do, is add a ref attribute to the element we want to reference in our Javascript. The value of the ref attribute will be the name of it within the $ref property.


1 Answers

While it is technically possible to access $refs of nested children...

Vue.component('mycomponent', {      template: "#mycomponent",  });    new Vue({    el: '#app',    mounted() {      console.log(        'Second level <input>\'s value:',        this.$refs.myFirstLevelRefName.$refs.mySecondLevelRefName.value      )    }  })
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>    <template id="mycomponent">      <div>          <input ref="mySecondLevelRefName" value="Hello">      </div>  </template>    <div id="app">    <mycomponent ref="myFirstLevelRefName"></mycomponent>  </div>

A way of performing parent/deep child, or deep ancestor/sibling communication, for simple scenarios, is using an event hub. (For complex scenarios, see Vuex.)

You would create a global variable:

var eventHub = new Vue(); // use a Vue instance as event hub 

To emit events you would use in any component:

eventHub.$emit('myevent', 'some value'); 

You would, then, in any other component, to listen to that event. The action of that event could be anything, including a method call (which is what you want):

eventHub.$on('myevent', (e) => {     console.log('myevent received', e)     // this.callSomeMethod(); }); 

Demo:

var eventHub = new Vue(); // use a Vue instance as event hub    Vue.component('component-first', {      template: "#component-1st",      methods: {        myMethod() {          eventHub.$emit('myevent', 'some value');        }      }  });  Vue.component('component-second', {template: "#component-2nd"});  Vue.component('component-third', {    template: "#component-3rd",    created() {      eventHub.$on('myevent', (e) => {        this.check();      });    },    methods: {      check() {        console.log('check method called at 3rd level child');      }    }  })    new Vue({    el: '#app',    data: {      message: 'Hello Vue.js!'    }  })
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>    <template id="component-1st">      <div>          1st level component          <button @click="myMethod">Trigger event at 1st level component that will call 3rd level child's method</button>          <hr>          <component-second></component-second>      </div>  </template>  <template id="component-2nd">      <div>          <component-third></component-third>      </div>  </template>  <template id="component-3rd">      <div><h1>3rd level child</h1></div>  </template>    <div id="app">    <component-first></component-first>  </div>

Note: If creating a dedicated instance as event hub is something complicated in your environment, you can replace eventHub with this.$root (inside your components) and use your own Vue instance as hub.

like image 69
acdcjunior Avatar answered Oct 09 '22 07:10

acdcjunior