Cas
Cas

Reputation: 395

Vue components communication

I have two Vue components:

Vue.component('A', {});

Vue.component('B', {});

How can I access component A from component B? How does the communication work between the components?

Upvotes: 34

Views: 15851

Answers (6)

0_o
0_o

Reputation: 497

Communication between the components can also be established by creating a single global event hub in your Vue application. Something like this:-

var bus = new Vue();

Now you can create custom events and listen to them from any component.

     // A.vue
    // ...
    doThis() {
        // do the job
    
        bus.$emit('done-this');
    }
    
    // B.vue
    // ...
       method:{
             foo: function()
          }
    created() {
        bus.$on('done-this', foo);
    }

More about this can be found from official documentation..

Upvotes: 8

lukas_o
lukas_o

Reputation: 4256

It's best practice to use props and events.

There are many examples online, like:

I recommend some reading on the topic.

If the components are siblings and have no parent-child relationship it might be worth checking the architecture of your app.

  • Do A and B have a parent child relationship?
  • Is there a component C that is possibly the parent of A and B?

If A and B are children of C, consider using props and events. Another way is to use props and sync, which can be helpful for form data:

Upvotes: 3

Suhas Bhosale
Suhas Bhosale

Reputation: 96

Communicate between two Vuejs components has many options. If your components are parent and child then you should use "props" to send data from parent to child and use "events" to communicate from child to parent. If your components are sibling then you need to use "store" else you can use "$root" property.

Parent to child

parent component

<ChildComponent :propsData="dataToPassToChild" />

child component must have property

props: ['propsData']

Child to Parent

child component

this.$emit('messegeToParent', arg1, arg2, ...);

parent component

<ChildComponent @messageToParent="messageReceivedFromChild" />

The below method should be in child component

messageReceivedFromChild(arg1, arg2, ...) {

}

Sibling components

component 1

this.$root.$emit('message1', arg1, arg2, ...);

component 2

this.$root.$on('message1', (arg1, arg2, ...) => {

});

Upvotes: 0

James Westgate
James Westgate

Reputation: 11454

For sibling to sibling communication, I found using the parent as an event bus made the logic fairly trivial. Using $root as an event bus meant additional code to check the scope of components that may not be direct siblings. Using the $parent means that the scope of the events emitted can be controlled.

The following example is for a TableHeader component. When clicked it re-orders the data in a table, other headers are no longer active and should not be displayed as such, a computed property cssClass is used for this.

export default {
    name: 'TableHeader',
    props: ['sort'],
    data() {
        return {
            direction: this.sort
        }
    },
    computed: {
        cssClass() {
            if (this.direction === 'none') return '';
            return (this.direction === 'descending') ? 'headerSortUp': 'headerSortDown';
        }
    },
    methods: {
        clickHeader(event) {
            this.direction = (this.direction === 'none' || this.direction === 'descending') ? 'ascending' : 'descending';

            //We use the parent as an event bus
            this.$parent.$emit('TableHeader:sortChanged', this);
        },
        sortChanged(element) {
            //Dont reset if this is the emitter         
            if (this === element) return; 

            this.direction = 'none';
        }
    },      
    created() {
        this.$parent.$on('TableHeader:sortChanged', this.sortChanged);
    },
    beforeDestroy: function () {
        this.$parent.$off('TableHeader:sortChanged', this.sortChanged)
    }
}

Upvotes: 0

pesla
pesla

Reputation: 1254

Cross-component communication doesn't get much attention in the Vue.js docs, nor are there many tutorials that cover this subject. As components should be isolated, you should never "access" a component directly. This would tightly couple the components together, and thats exactly what you want to prevent doing.

Javascript has an excellent method for communication: events. Vue.js has a built-in event system, mainly used for parent-child communication. From the docs:

Although you can directly access a Vue instance’s children and parent, it is more convenient to use the built-in event system for cross-component communication. It also makes your code less coupled and easier to maintain. Once a parent-child relationship is established, you can dispatch and trigger events using each component’s event instance methods.

Their example code to illustrate the event system:

var parent = new Vue({
  template: '<div><child></child></div>',
  created: function () {
    this.$on('child-created', function (child) {
      console.log('new child created: ')
      console.log(child)
    })
  },
  components: {
    child: {
      created: function () {
        this.$dispatch('child-created', this)
      }
    }
  }
}).$mount()

Dan Holloran has recently written a piece on his "struggle" with cross-component messaging, in two pieces. This might be helpful to you if you need communication between components that have no parent-child relationship.

Another approach I have experience with (other than using events for communication), is using a central component registry that has a reference to the public API with an instance of a component bound to it. The registry handles requests for a component and returns its public API.

In the context of Vue.js, events would by my weapon of choice.

Upvotes: 33

Warwick
Warwick

Reputation: 429

In addition to pesla' answer take a look at the guide's State Management section under Building large scale apps: http://vuejs.org/guide/application.html#State_Management . I've created a jsfiddle based on that here: https://jsfiddle.net/WarwickGrigg/xmpLg92c/.

This technique works for components too: parent-child, sibling-sibling component relationships etc.

var hub = {
  state: {
    message: 'Hello!'
  }
}

var vmA = new Vue({
    el: '#appA',
    data: {
      pState: {
        dA: "hello A" 
    },
    hubState: hub.state
  }
})

var vmB = new Vue({
    el: '#appB',
    data: {
      pState: {
        dB: "hello B"
    },
    hubState: hub.state
  }
})

Upvotes: 12

Related Questions