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

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.

Related

Differences between Vue.component and new Vue?

Please tell me what are the differences between Vue.component and new Vue.
The second parameter of the Vue.component method ( the options object ), is the same first parameter of new Vue constructor. right?
Are there any differences between two methods, in meaning and parameter options?
Thanks
Let's introduce both of them first and we'll talk about the difference after it.
What is New Vue?
using new Vue we create a new vue instance; Every Vue application starts by creating a new Vue instance with the Vue function like following:
var vm = new Vue({
// you'r options here
})
According to official docs(this link):
A Vue application consists of a root Vue instance created with new Vue, optionally organized into a tree of nested, reusable components.
now that we know what vue instance is let's take a look at components.
What is Vue.component?
Components are reusable Vue instances with a name and we can use them as custom elements inside a root Vue instance
What are the differences?
Since components are reusable Vue instances, they accept the same options as new Vue, such as data, computed, watch, methods, and lifecycle hooks. The only exceptions are a few root-specific options like el.
A root Vue instance is a Vue application launcher, Vue component is an extension of the Vue instance.
Read this post for additional info.
When you call new Vue(), you're creating what is called a vue instance. A Vue instance basically is a JavaScript object that has some capabilities to interact with the DOM.
Vue components happen to be Vue instances, too. But the main difference is that components belong to other components/vue instances, while bare instances are mounted directly into an existing element of the DOM (with existing, I mean HTML that is not generated by Vue and existed previously to the instance creation).
So, basically, the main difference comes from the use: you usually create a bare Vue instance with new Vue when you need to attach that instance directly to the DOM as your root element. Vue components, on the other hand, are always attached to ** other components**.
In general, it is really common to have a single root vue instance in your Vue application, but you could have several bare instances in the same web page: you could get creative and span several Vue instances and make them interact with the DOM at the same time, as if they were components.
However, it is better to have a single root element with several components, since it is easier to reason about your code in that way, and also facilitates the use of plugins like Vuex or Vue-router.
Maybe this link about this matter can serve you as well.

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.

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

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

How to set data value of other component in vue js?

I have two component for example Login.vue and Header.vue. I want to set data value of header.vue after some action in login.vue. how can i do so?I am using vue cli.
If your Login Component is a child of your header, then your Login can emit an event. See here.
If not, then your components can exchange data via a Global Event Bus
or a global store Vuex.
Also take a look here on cross component communication.

Differences between vue instance and vue component?

I'm new to vue js and have some questions when learning it.
I'm now a little confused about the relationship between its instance and component. As far as I learned, every app build by vue should only have one instance and one instance only, it can have as many components as you like if needed. But recently I've seen a demo, and in that demo it has more than one instance.
So my question is, is that ok to have multiple intances in one app( the demo code works fine, but is that the correct way)? What's the best practice to use instance and component in vue app?
It's ok to have two instances in the same project, however, you probably don't want to do that.
A good scenario is to have one main instance to control your app, specially if you are creating a Single Page Application (SPA). Then use as many components as you want.
Components are a great way to reuse code and keep it organized, and, with Vue.js, is very easy to communicate between your components and your "main" Vue instance.
It depends very much on your situation.
I work on a large web project which is not an SPA. We have a Vue instance for each "silo" of the application. We are slowly transitioning an older project from a mostly jQuery frontend so it's possible that as it evolves We'll be able to condense down to a single Vue instance but we're having no trouble with multiple instances. The ease of using Vue in existing projects was one of the biggest deciding factors in choosing it over another library such as react.
I have taken a different approach with green development, one instance and many components.
There are something in common, and some difference between Vue instance and Vue component.
From Vue docs:
all Vue components are also Vue instances, and so accept the same options object (except for a few root-specific options).
The root Vue instances accept properties like el, router, the Vue components cannot.
The data property in root Vue instances is an object, but in Vue components must be a function.
The design target is different:
A root Vue instance is a Vue application launcher, Vue component is an extension of the Vue instance.
Vue components can create elements to be reused in many places. This is Vue characteristic of componentization mainly reflect point.
Vue instance can associated with and manipulate an element which is already exist.
Vue component more suitable for create new element and reuse it at anywhere.
Think of a Vue Component as a blueprint or set of rules on how to create something that can be inserted into the DOM that the user can interact with.
So when you create a Vue file you are going to define exactly one component with a set of rules that tells Vue how to display stuff on the screen and tells a user how to interact with it.
On the other hand is a Vue instance, its an instance of a Vue component, it represents something that has been inserted into the DOM and is something that a user can interact with.
If you have a background in Object-Oriented Programming, think of a Vue Component as being like a class and a Vue instance as an instance of that class.
What has not been mentioned in previous answers that I will cover in regards to the difference between Vue instance and Vue component is how we define the data property that we are working with.
If we are working with a Vue instance, then we can define the data property as an object or a function that returns an object like so:
With a Vue Component that data property must be a function that returns an object.
So for example this is a Vue component:
export default {
name: "App",
components: {
SearchBar,
VideoList
},
And if we want to make use of data inside of that Vue component, we have to make a function that returns an object.
Vue components extends Vue instances
but Vue instances accept properties like el, router, the Vue components cannot.
best practice:
one Vue instance
many Vue component