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.
Related
I have a link element injected into translation string that I later consume via aurelia-i18n plugin. I need to listen for a click event on this link. As far as I researched it is not possible to add click.trigger="function() to an html element in translation string.
So I ended up just manually assigning a listener to the link DOM element in attached method of parent component. However when language updates, link updates as well and my listener is gone. Is there a way to know when component has been updated so I could reassign the listener there?
Or is a better solution to this issues?
I am new in VUE.JS but i have finished some beginner courses of vuemastery. Though I know how to bind properties and how to emit custom events, I have a problem: I don't know how to make these things through multiple levels of components.
Let's say we have the following hierarchy:
I need to have control on the Home component's properties from the Elements and Input components from the bottom of the diagram. Right now I am emitting custom events from level to level from down to up, but it doesn't look like an elegant solution.
Is there a better way to do this? And of course when I change one of the properties from Input component it need to have effect on the properties in the Element components as well.
For example the Element components are elements having width and height calculated based on totalWidth property, which can be edited in the Input component. I'm having here a warn as well in the console: [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders.
Use this.$root.$emit to emit event on the root component, that would then propagate event on its child components, regardless of depth level
I would recommend using vuex to manage the state of your application. Emitting events all over the place is not the most elegant solution.
I have a component that represents an option in a form, with data representing the currently selected option. There is a parent component which represents the full form, with a submit button and a reset button. I keep track of what options are currently selected in the form by emitting events from the child to the parent (this is important because the form updates dynamically)
.
I'm trying to design the reset button, which clears all fields in the form (sets the currently selected option to an empty string). I would need to modify the data of the child component. Should I do this using a Vue instance as a bus? That seems overkill. Is there a better way to design these components?
I think you want to use sync on the properties your passing into the child component. I use it to load my child component like:
<textbox :content.sync="new_comment" placeholder="Add a comment..."></textbox>
If you already emitting from your child component then changes to new_comment will automatically be passed through.
You can find a lot of ways to do this here.
For me, after a lot of playing around with props, i found that the best and safest way is to use this.$refs.
Even if you have more than one child component with the same ref name, you can go through each child with a forEach.
You can create a custom event to listen to the reset button on each form field. Check out the documentation for this here
Just put a method in the child, perhaps Clear, and call it from the parent. You use $refs in the parent to get to the children.
Can somebody provide an example of sending an event from parent to child in Polymer 2.o custom element?
I tried with following:
<child-element>
this.addEventListener('dbinit', this._evdbInitStatus);
and
<parent-element>
this.dispatchEvent(new CustomEvent('dbinit', {detail: {kicked: true}}));
The call back does not get invoked.
This is not really related to Polymer itself, as you can see in the documentation on how events work, here, events capturing stops at the element that triggered the event and the event bubbling (as the name suggests, the events bubble up) starts from the element and goes up in the tree.
So, in other words, an event fired by a parent element won't be captured by a child element. You will need to use a data binding to pass data down.
To keep a consistent, predictable flow of data, in general, it's better anyway if data travels down via data binding and up via events.
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.