Pass Click Event to two components up Vuejs - vue.js

how could a pass a click event from one component to two parents up.
I have a form with a bottom clear, this form component is in a file filterForm
the filterform component is called in another file called TableView and the tableView component is called in a file called Admin
I want to execute a function inside admin when the button clear is clicked
the button is in the file filterForm
the filterForm is used in TableView
and tableView is used in Admin
this is the function I want to call from Admin to test
I understand that I have to make a click event from fileForm and emit that event to Tableview, but the function is on Admin that contains all the data and methods.
Thanks for your help!

Based on $emit event in Vue.js: https://vuejs.org/guide/components/events.html
When you emit an event like this: $emit('someEvent'), the parent someEvent function will fire (and also you can pass some parameters).
Passing a data or emitting a function so that two parents up listens to your event and get the data will need some chaining.
Fire the event on 1st component and get it in 2nd component and then fire the event in 2nd component to get it in 3rd.
Edit: one of the best practices is to use Vuex(Pinia) as a state management tool to pass or get data in an easier and cleaner way.

Related

Vue component loses input when asynchronous call updates another property

I have a component that has an <input> with a :value set to a certain property. The component has another property unrelated to this input, which can get updated asynchronously (AJAX call). Whenever you're typing inside the input and the asynchronous call finishes, updating the other property, your typed input is reset.
To recreate this problem I've created a jsfiddle using a setInterval to simulate the async call and increment the other passed property. Try typing in the input, it will get reset every second. If you're quick enough, you can tab out and cause the #change to trigger the actual update.
The question is: why is the update to the other prop invalidating/rerendering the component and how can I work around this?
Note that v-model="person.name" is not a valid solution here - I need to know the old and new value, which is why I'm using a manual :value/#change combo.
Edit: The updateName method also really only needs to be triggered when the user leaves the input field. This is because the code run inside it is relatively CPU intensive and only needs to run when the user is done with the input and leaves it (in my actual code, not the jsfiddle).
Edit2: Is there some way to not let it re-render the entire component, but only the relevant pieces?
Because the parent component is changing a property of the child component, it has to re-render (parts of) the child component. Since you are using #change, instead of #input, your changes are not saved yet to the reactive variable person.name, it only works if you click tab quick enough. One solution would be to change #change to #input (which better resembles v-model):
https://jsfiddle.net/mf67xq1e/
Another (better) option is to use v-model and use a watcher to retrieve both the old and the new value:
watch: {
// whenever person.name changes, this function will run
"person.name": function (newName, oldName) {
console.log("newName:", newName);
console.log("newName:", oldName);
}
}
https://jsfiddle.net/mf67xq1e/1/
EDIT:
As you mentioned you only need to trigger something when you blur/leave the input field, seperate the reactivity of the variable and the triggering of your other method (e.g. updating some other variable or something), in two seperate variables:
https://jsfiddle.net/ta9cgnx0/
EDIT 2: Cleaner option with v-model and a seperate call for your other trigger on blur:
https://jsfiddle.net/ay1g63u8/

Emit data between components (Event listener in vue?)

I'm kind of new to Vue and I'm trying to emit data between different components.
I have 2 components I need to emit their data together:
First component is the Item Selector.
Second component is Filter Navigation Bar.
the logic:
The navigation bar contains a filter section, I've created an ItemSelector component and import it to the navigation bar.
I want the data selected in the item selector will be emited to the container and a table will be draw by that information.
I created the logic of the table, and tried to import the item selector component directly to the container and passing the data using emit, and it worked great.
The problem is I've added one more page to the cycle.
Right now, the ItemSelector component emits its data to the FilterContainer component, and now this data should be emited to the container!
Is there any way to catch all those events in a seperate component, compute the data and emit it all over the app?
You can use a global event bus which can listen/emit event on global scope of your app.
Another approach is using vuex which store all global states of your app.
If you have small app, i think you should use event bus because it simpler than vuex.

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.

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.

Communicating with Knockout components

Is there a way to communicate from the parent viewmodel to a KnockoutJS component?
I have a component that contains a bootstrap modal dialog box, to search for customers and return a selected customer. At present, to make the dialog box appear, I pass an observable boolean from the viewmodel in the component's params attribute. To make the dialog appear I set this to true, which invokes the dialog box. I also pass a callback function in params to return the results.
Here is a fiddle demo which shows the concept: http://jsfiddle.net/Quango/5bxbsLt6/
Passing the observable boolean to invoke the dialog doesn't feel right, but it's the only working solution I have. The only other idea I had was to use ko-postbox to create a publish/subscribe function.
It feels like there should be a way to invoke actions, e.g. component.Show() ?
I think the answer here is that there isn't a better way. To communicate from a parent viewmodel to the component, pass an observable value, and then use that directly or subscribe to changes in the component.
I will put a suggestion on the Knockout github project to consider some form of interface.