Passing events from nested children(s) to parent in Vue - vuejs2

Im working on a Vue component that will be re-used in different projects (and will be available via npm install ...) and have principal question how the event emitting is handled.
The component itself contains few nested children elements like:
component-parent
|-child 1
|-child 2
|-child 3
|-child 4
When the component is included in some project then component-parent will expose all events that are emitted from the whole component. And was wandering how the in-component events are passed to the component-parent. For example if i want to pass event from child 4 to component-parent then child 4 emits to child 3 which emits to child 2 which finally emits to component-parent.
Such workflow is working fine but it doesn't look very practical.
Ive found out that EventBus can be used and seems more elegant solution but also seems that its not very popular. Is EventBus can be used freely or its considered to be a bit hacky/workaround way?
And another question regarding using vuex. If vuex is included in the component itself is it possible to emit from it to the project component (that have my component included)? Including vuex in my component will lead the main project to have two vuex instances. Is there are blockers for having multiple stores like this?

After some testing I've decided to go with EventBus. EventBus allows sending/receiving events between components. The components can be part of the same parent tree or on a complete different one. More information here
But in general event-bus.js file should be created
import Vue from 'vue';
export const EventBus = new Vue();
And then imported in any component that will use the EventBus mechanism
<script>
// Import the EventBus we just created.
import { EventBus } from './event-bus.js';
...
Then from the sending component emit the event
EventBus.$emit('i-got-clicked', this.clickCount);
Any component that have loaded EventBus can listen for events like this:
EventBus.$on('i-got-clicked', clickCount => {
console.log(`Oh, that's nice. It's gotten ${clickCount} clicks! :)`)
});
To stop listen for events:
EventBus.$off('i-got-clicked');
Personally i find EventBus quite easy and useful but I'll probably use them only when developing components that will be included in another projects. For the same project components Vuex is more than enough

Related

Accessing pinia store through a parent component

I am following a tutorial on udemy. But instead of using Vue 2 and Vuex I use Vue 3 and Pinia. It works almost. One thing I can't seem to fix like the writer does.
I made a child component that has a click event to delete a task in pinia. The thing is
he uses
#click="$store.dispatch('deleteTask', task.id)"
And he states that you don't need to import the vuex store etc in the child component. But when trying to do this with pinia i always get a deleteTask not defined. When importing the store in the child component it works. Is this even possible with pinia? I us:
#click.stop='useTasks.deleteTask(task.id)'
I got answer from the udemy guy. And i searched on pinia docs for more answers but it seems you always need to import the store in the child component. Not like you could doe with vuex

How do I run a function on a different component with vuex (non parent/child components)

I have 2 non parent/child components.
I'd like to run a function on component A by clicking a button on component B.
I know that the eventbus is a solution but because I am already using Vuex I would like to do it the Vuex way but could not find an example on the internet.
Have component A mutate some state that component B is watching. When component B see's a change to that state, run your function.
The mutation could be as simple as flipping a boolean or incrementing a number. Anything to trigger the watch in the other component.
Here is how to setup the watch: https://stackoverflow.com/a/44347195/1409310

Vue JS Components structure

I am learning Vue and my doubt is about the structure of my Vue app.
I learnt that the components can include both logic and template. Then I separated my components and everyone is getting the config from the main app (config is an object with the coordinates config.ll, config.lng).
I do the ajax call to my search-and-discovery API service and I display the results inside each components (current location, venues-near-you etc).
My question is: is it correct to encapsulate the calls into each components? Or is it better to get the needed data inside the general app and then share the results with the components using pros?
I am asking that because the hard part is starting now when I want to communicate the click of a category to the venuesNearYou component, I tried to use the emit without success.
//MAIN
<sidebar :config="config"></sidebar>
<content :config="config"></content>
//IN SIDEBAR
<currentLocation :config="config"></currentLocation>
<categories :config="config"></categories>
//IN CONTENT
<venueDetails :config="config"></venueDetails>
<venuesNearYou :config="config"></venuesNearYou>
I think you could use event Bus like approach
we have three type of communication in vue app (without vuex)
Parent to child communication which is full field by props
child to parent communication handle by custom event from child which is listen by parent
communication between non parent child component in which we use event bus approach
Parent to child example
Child to parent example
In child this.$emit('sendDataToParent',{someData:"some data"}})
in parent
<child-component :somedata="dataToChild" #sendDataToParent="'gotsomedata from parent'">
Event Bus
in main vue instance
const eventBus = new Vue()
in some component from where to send data
import eventBus
eventBus.$emit('someEvent','some data')
in some component from where to receive data
created() {
// register listener
eventBus.$on('someEvent',()=>{
})
}
For more reference
https://v2.vuejs.org/v2/guide/components.html#Passing-Data-to-Child-Components-with-Props
https://v2.vuejs.org/v2/guide/components.html#Emitting-a-Value-With-an-Event
https://medium.com/easyread/vue-as-event-bus-life-is-happier-7a04fe5231e1
It's hard to help you around emitting an event since you didn't provide much of a code. But check Vuex. It serves as a centralized store for all the components in Vue application.

Vue - use Events, Event Bus, or Vuex for showing components

I'm currently building a larger scale vue application. For global state management I use vuex of course. However, I came across the question of how to show or hide really simple components. For example I have a navbar which can open up a bug form modal component. I also have a sidebar component which can be either visible or non-visible. From within these components I want to be able to close them in the parent. Own mutations in vuex seem a little bit overkill for simply toggling the visibility of a child component, also I don't want the store to get bloated by these things.
My question now is, how I should handle showing these components. I can think of 3 different solutions:
1) Use solely Vuex for everything, with own actions, getters and methods for showing or hiding simple components.
2) Use an Event Bus to show these components along with vuex for storing user data like email for example
3) Just emitting events in the child component and listening to it in parent component

vuejs2 - how to create event buses for single file component hierarchies

I've found a solution by LinusBorg here, that registers a bus globally in any Vue instance. Is there a way to define this in a component hierarchy instead, so that I can create multiple scoped busses? Basically, if I had multiple "root"-level components with some children, an event bus should be instanciated for the "root"-level component and it's children, rather than all Vue instances.
I can't use the simple $emit and $on, because the hierarchy isn't restricted to plain parent-child communication. So events have to be passed over multiple levels.
You can create a js file like eventBus.js, and just export a vue instance:
import Vue from 'vue'
const bus = new Vue()
export default bus
then you can import the event bus in your .vue file
import bus from 'path/to/eventBus'
...
bus.$on('foo', ...)
Update my answer from the discussion in comments:
Since a event name is just a string, you can add a prefix/namespace to the event, like bus.$emit('domain.foo') or bus.$emit('domain/foo').
If you feel your application becomes more and more complex, just go for vuex.