I want to trigger a function from another component which is not parents and child relationship. i try to use eventbus, but i am not sure am i implemented it correctly, since the function is not working. i have created a boot file eventBus.js and added it into the quasar config, but its still not working. Anyone can help me to check which part did i implemented wrongly?
eventBus.js
import Vue from 'vue'
const eventBus = new Vue();
export default eventBus
Vue.prototype.$eventBus = eventBus;
below is the function that i want to get from this page, (this.getSchedule(), it is working perfectly on current page).
mounted(){
this.$eventBus.$on("refreshListSchedule", ()=>{
scheduleDate = this.scheduleDate
console.log(scheduleDate)
console.log("Testing successed")
this.getSchedule()
})
},
The page that i want to trigger it
this.$eventBus.$emit('refreshListSchedule')
It is better if you manually import from eventBus.js in each component where you want to emit or subscribe for events - don't rely on Vue.prototype.
And don't forget to unsubscribe in the beforeDestroy hook.
Related
I have just completely upgraded my project to Vue2.7, which a backported support for Vue3 feature.
Like what I try is, get the object the in vue instance chain, such as
import Vue from 'vue'; Vue.prototype.$http = http; but no any method or hook such as createApp supported in vue2.7, so how to I access it(the $http) in my component?
only what I can do for now just console.log(getCurrentInstance()).
And finally get it by getCurrentInstance().proxy.__proto__.__proto__.$http, such unpleasant code, is it any other better shortcut to do this? Thanks.
I would suggest using provide/inject to make the axios available in all your components.
https://vuejs.org/guide/components/provide-inject.html
Find out the way by warmed-heart people Jacek, just use provide and inject to solve it.
Just like
const vue = new Vue({
setup() {
provide('http', http)
}, ...
}
In my Vue3 app, I'm using the mitt eventbus library to emit and receive events between components.
I put this in onMounted of a list component that needs to refresh:
mitt.on("list_refresh", (evt) => {
refresh();
});
In another component that contains the list-component as a child (or grandchild), I do this in a method:
mitt.emit("list_refresh", {});
This works ok, but while developing with hot-reload on, the events seem to be emitted multiple times, as if they're created extra each time the app reloads, instead of overwriting the old ones.
When I reload the entire page in the browser, it works fine again.
Any idea to prevent this?
It looks like your component is missing a corresponding off() call to remove the event listener. During hot reload, the current component instances unmount, and new ones mount; so if you're not removing current event listeners, you'll just pile on new event listeners. To resolve the issue, use the onUnmounted hook to remove the event listener when the component is removed from the DOM.
Also, make sure to pass cached function references (instead of inline functions) to mitt.on() and mitt.off() to ensure the given event listener lookup succeeds in mitt.off():
// mitt.on('list_refresh', () => refresh()) ❌
mitt.on('list_refresh', refresh) ✅
mitt.off('list_refresh', refresh)
Your setup() should look similar to this:
import { onMounted, onUnmounted } from 'vue'
export default {
setup() {
const refresh = () => { /*...*/ }
onMounted(() => mitt.on('list_refresh', refresh))
onUnmounted(() => mitt.off('list_refresh', refresh)) 👈
}
}
im wondering how can i use this.$eventHub.$emit('something');
But inside of vuex
the reason why i need this is because im using a plugin (vuex-persist-indexeddb), and there is a method called rehydrated (which fires when the db is loaded) so i want to emit an event on eventHub for warn the db is loaded...
i made the eventHub like this in the main.js file:
Vue.prototype.$eventHub = new Vue(); // Global event bus
In my store/index.js file ive loaded Vue but it doesnt recognize the $eventHub called from Vue.$eventHub...
imported with:
import Vue from "vue";
Hope anyone can help me, thanks in advice
i've already solved it :)
the solution was create a new folder/file like this:
folder: eventHub/index.js
file contents:
import Vue from "vue";
const eventBus = new Vue()
export default eventBus
and then in the router file simple import and use
import eventHub from '#/eventHub'
eventHub.$emit('something');
pulled from the official docs:
vue docs events
I have an async js script which is loaded at the top of index.html in my vue project. This script exposes several functions into the window object which I would like to be able to call. I would like to be able to call these functions in the mounted() lifecycle hook, but the async function appears to complete only after mounted has finished. Is there a way I can force the vue instance to wait for all <script> to complete before mounting the root component?
According to this issue in Github https://github.com/vuejs/vue/issues/7209 it seems that the async hooks in Vue lifecycle mounted() created() etc, is only for the ability to call async functions. but the lifecycle itself is synchronous.
Here are some ideas to manage this problem:
You can wrap your component with v-if and render it just as soon as your data is ready.
If you render a component by router - you can use the lifecycle of Vue router. and call your async function before enter to Vue page. do it like this:
export default {
beforeRouteEnter (to, from, next) {
// called before the route that renders this component is confirmed.
next()
}
}
this next() function calls the first Vue lifecycle hook...
full tutorial: https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards
If anyone is interested, here is how I solved my problem:
I modified the js file that the <script> was referencing to set global.initComplete=false initially, and when the script was complete, I marked it as true.
For main.js file, I used:
import Vue from 'vue'
import App from './App.vue'
function init() {
let vm = await new Vue({
render: h => h(App),
})
if(!global.initComplete) {
setTimeout(init, 50)
} else {
vm.$mount('#app')
}
}
init()
In my custom library I have several components which run ajax requests, and when a given request fails the component emits an error event.
Then, in my main component I want to listen to all error events emmited and run the method handleErrors, but for that I have to go on every component and add #error="handleErrors".
Is there a way to configure my main component to catch error events dynamically and call handleErrors without going on each component and adding it? Preferrably changes to the main component only.
You can use the EventBus system in Vue instance. Actually EventBus is a different Vue instance your Main Vue instance. You make your own Event bus system.$emit, $on and $off events.
event-bus.js
import Vue from 'vue';
export const EventBus = new Vue();
and now you are ready to use.
some-component.vue
// Import the EventBus.
import { EventBus } from './event-bus.js';
// Send the event on a channel (eventName) with a payload (the click count.)
EventBus.$emit('eventName', this.clickCount);
other-component.vue
// Import the EventBus.
import { EventBus } from './event-bus.js';
// Listen for the eventName event and its payload.
EventBus.$on('eventName', clickCount => {
console.log(clickCount)
});
// Stop listening.
EventBus.$off('eventName');
more information and example
https://alligator.io/vuejs/global-event-bus/
Figured a way to do it without refactoring the individual components: just injected the listener in every component using a mixin.
The result:
// Before starting up the main instance:
Vue.mixin({
created: function() {
this.$on('error', function(error) {
// Then I handled the errors here.
);
}
});