Selecting data from multiple Treeview components in Vuejs - vuejs2

I have multiple vuetify treeviews in vue and I want to retrieve the node name from each treeview according to which I select. This is sort of a merge tool with a treeview on the left and one of the right. Using selected.name as a model on the middle template to display this is only getting my right treeview selection (and it's not dependent on the first tree I click). How do you differentiate between the two trees based upon node click/select please?

One way of dealing with this is to emit different events from each of the treeviews. You could have a prop of type string on your treeview component which you append/prepend to any events emited.
Meaning, if before the Treeview emitted the event 'hello', you can pass in the prop 'left-tree' for the left Treeview, and have your event inside of the Treeview component emit 'left-tree-hello' for example. For the right Treeview, you'd pass in 'right-tree', thus emitting 'right-tree-hello'.
Alternatively, you can just have different event listeners on your parent component, one for the left one and another for the right.

Related

Binding and custom event triggering on multiple level in VUE.JS

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.

TreeView component

I trying to create tree view component (something like this https://www.jstree.com/), where I can turn on edit mode and select which one should be visible. I tried different ways, but none of them worked properly. I would like to have access to selected tree and entire tree from outer component, so it probably should be reactive.
It's not reactive, because of nested arrays (children).
How to reproduce:
Click Edit in left tree
Click Expand all on both tree
Click some
nested checkboxes
Right tree view should changed, but it doesn't.
Live demo: https://jsfiddle.net/rs3hoktb/
*Yeah I know, I should avoid mutating props cause of One-Way Data Flow.

Modifying child data from parent vue

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.

Vue: how to fire an event on a sibling component

In Vuejs, I have a parent component (P), and two child components (C1 and C2). The parent has objects which it shares with both child components.
Component C1 displays the objects (in a table) and component C2 lets the user modify the properties of the shared objects. Because the objects are shared as objects, I am updating their properties directly in C2, and the changes are displayed in C1.
The problem is that C1 is responsible for saving changes (by making an ajax call to the server). If the user modifies a property directly in C1, it triggers the change event, and an event handler makes the call. However if the property is updated in C2, the change event is not fired in C1, so the change is not persisted.
So, the question is, how do I fire a change event in C1, based on an event in C2? I have an event bus in place (in the root element). I could (perhaps) use an event listener to grab the element (e.g. with jQuery), and fire the event, but obviously this is not the most elegant way to do it. What's the Vue way?
I hope I understood you correctly: You're sharing an object between two children and you're manipulating that object in either child component directly?
That pattern itself is the problem. You don't want to manipulate state inside a child component. The clean way that'll keep the reactiveness is to bind the object via a prop from the parent to both child components. The children should never manipulate the state of the prop object (vue should actually throw a warning if you do that), they should only emit an event that they want to change the object by using:
this.$emit('input', newObject)
Now simply listen to that event in the parent and manipulate the object there, or, for simplicity you can also use the v-model pattern as described here.
<c1 #input="myUpdateFunction" />
or with the v-model pattern
<c1 v-model="mySharedObject" />
That's it. If your other component has the same object bound to it as a prop as well, it'll update its template automatically.
If you want an even more elegant way to share state for an entire application I suggest using Vuex.
Your question it is not too clear.However you can use eventBus and it will work fine.
My recommendation though,is to use vuex.
You can manipulate the store properties and whenever the properties changing,the changes will be reactive and applied to all components.
So if you have two components c1 and c2,and in store you have a property name: 'John Doe'.
If in c1 component you change the name like: this.$store.state.name = 'Jane Doe' this change has also take effect to component c2.
Of course it is not so simple.In vuex store you should have state,getters,mutation,actions and on your components to use computed properties to use fetch the store properties though getters.

How to communicate between components within a certain component?

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.