Hi Guys, I'm not quite sure how to do this, I'm very new to Vue, how can I send my data from NewDeal component to DealsTable component? As you can see NewDeal has two parent components. I've read about $emit and $on, but just want to confirm if do I really need to do it like newDeal -> QuickActions -> SideBar? And I am not sure how to go from there if what I'm thinking is correct. I hope you can shed some light on me.
I've tried emitting an event from NewDeal component and listening it from the DealsTable component but didn't work, I am not sure if this is possible, or it should really be that the child is a direct descendant of the parent?
Thanks!
Fixed it using a global variable bus and replacing this by bus.
Declaration in app.js:
window.bus = new Vue({})
Emitter:
bus.$emit()
Listener:
bus.$on()
I've tried emitting an event from NewDeal component and listening it from the DealsTable component but didn't work
Looks like you have a solution but I thought I'd comment on this one part in case it helps. The reason that DealsTable didn't see the event from NewDeal is that vue events emitted by a child component are only propagated to the immediate parent component and no higher.
If you want the vue event to be seen higher up the chain then the child's parent would need to emit the event once it listened for the event and received it. In this way each parent could bubble the event up the chain but in many situations that's too complicated, and so your window.bus approach is the way to go. Hope that help make what you were seeing make more sense.
Related
I want to know the concept of the below thing-
I have created one component and set up its respected event listeners. Now, I want to remove those listeners on this component's beforeDestroy hook before redirecting to another route that will create another component.
but what I noticed is, beforeDestory hook of the first component is calling even after the second component's created hook.
I want to destroy the first component completely and then create another component.
// To set up the event listeners
created() {
this.EventBus.$on('myCustomEvent', payload => {
// some code here
)}
}
// To destroy the event listeners
beforeDestroy() {
this.EventBus.$off('myCustomEvent');
}
Any suggestions?
In search of an answer to your question, I came to the conclusion that it is better to refuse to use EventBus altogether.
Here is some information on this and some thoughts from there:
I have that feeling that having an EventBus in Vue is an anti-pattern, especially if you’re using VueX but I can’t quite put my finger on it. At the point you want to be sharing data like that, wouldn’t it be better to use a store to handle all of those “events” / “mutations”?
Also, looking at the solution to this issue, you are doing everything right and there is no other way.
I wonder how Vue2's $emit works?
On its API(https://v2.vuejs.org/v2/api/#vm-emit), it says:
Trigger an event on the current instance. Any additional arguments
will be passed into the listener’s callback function.
If current instance means the component defined, while its main usage is to send signal to parent(https://v2.vuejs.org/v2/guide/components.html#Sending-Messages-to-Parents-with-Events)
I wonder how to understand this(the way how the event passed is pretty confused to me)?
THanks
The wording on the docs might create confusion to some people.
Maybe something in the lines of: "Makes the vm current instance dispatch an event" would be clearer?
In the end it is just a classic pub/sub pattern: your component instance emits / dispatches / fires an event, and other components (typically the parent one) listen / subscribe (v-on / #) to that event.
Simply put, $emit register an event in a component, and then you can listen to this event in other places wherever the component is used.
Say if you have a Child.vue and somewhere in this component, you did:
.$emit('some-event')
Then you can listen to this event when Child component is reused, for instance in another component SomeComponent.vue, you can do:
<template>
<child #some-event="doSomething"></child>
</template>
So here the event is triggered in the child component, but you decide what to do in the parent component with doSomething. Hope this makes sense!
Suppose I have a tree of component like this:
<widget>
<widget-header>
<panel-toggle></panel-toggle>
</widget-header>
<widget-body>
<panel></panel>
</widget-body>
</widget>
Now supposed I want the panel-toggle component to be able to toggle the visibility of the panel component. I could have it affect a prop passed down from widget through to each component, but that didn't seem like the best solution. I tried sending an event with this.$emit(eventName) but the event is only picked up by the immediate parent of the element emitting the event. In this case, that would be panel-toggle emitting the event and only widget-header being able to pick it up. I tried sending the event across the root element with this.$root.$emit(eventName) and picking it up with this.$root.$on(eventName), but then it is picked up by all widget components and that is no good. What I ended up doing is sending the event with this.$parent.$parent.$emit(eventName) and then picking it up from panel with this.$parent.$parent.$on(eventName). While that worked, it doesn't seem like the right way to go about this.
What would be the correct way to achieve this communication between components within the component widget only with Vue? Is the answer somehow related to the ref feature?
Since you're concerned (and with good reason) about the globalness of a global event bus, the solution is a localized event bus. Create a data item in the parent:
panelBus: new Vue()
and pass it to each of the children as a prop. Now they have a private communcation channel for just the two of them.
I was Vue.js now for a project and created and used a lot of components.
Now I started to have the problem of having too many eventemitters and props that I need to keep track of.
I guess to illustrate the problem the best I will use an example:
Lets say you have a main.vue and 2 or 3 Components.
One contains a button that should manipulate the other 2 components or switch them out.
Now I need to emit an event to the main.vue and then main.vue has to change a binded variable and pass props down to the other 2 components.
Alright: Now lets put the button in a component of of a component. You need to make sure that every link between a parent and a child is correct.
Now create a bit project and put a button in another components and you have to change everything.
So is there a good way to avoid this?
Something like a broadcast function so that every component is receiving the event?
Or a Manager that is handling the communication of all components?
use a flux pattern (vuex)
At first you may think that this does not really answer the question, since it deals with storage of data, and not handling of events. The flux pattern changes the architecture of your application by creating a single store (think database) that all components can read and write from. Coupled with the reactive nature of the reactive frameworks such as vue (or react), the components will react to a change in data. So instead of tightly coupling component A to D through B and C, you'd have component A listen to mutations in object X, and component D makes changes to object X. When the change happens, component A gets updated without having to listen to any of the children's $emit functions firing. At first it may seem daunting, but the investment is worthwhile.
I have a requestion, how about vue.js's common component's best practice when communicating with different parent component.
for example, in my scenario, a basic modal component, trigger a 'close' method, but it has two different parent component
I find two solutions:
parent need pass an additional prop, and then baisc component just
trigger event which event's name is the prop value, so the listener
parent component attched on could be called
in basic modal just use this.$parent to visit parent component methods, or this.$parent.trigger('xxx'), and then parent knows what to do
But, both above I think not very good, the first may need pass an additional prop, this let others who write a third, a forth parent component use the basic component not very handy. And the second may be felt more hard coded.
So, is there is better solution in this case?
Use this.$dispatch('eventName', data) (for Vue 2.x, use this.$emit('eventName', data)), to trigger an event to any parent, grandparent and further up the chain (you can use this.$broadcast('eventName', data) to trigger events down the chain in Vue < 2.x).
If the parent has an event called 'eventName' then it will fire this event.
If you have multiple parents, you can give them each a different event and from the child fire this specific event via dispatch. You can also give each parent the same event and pass a data prop that specifies what the parent should do. Third option is to refer to the specific parent:
var parent = new Vue({ el: '#parent' })
// access child component instance
parent.$refs.eventName()
Each option has pros and cons. The best solution depends on the context. But I think that the best solution in general is option 1. Then you don't need an additional data parameter. Option 3 is not loosely coupled.
For more info: https://vuejs.org/guide/components.html