I'm working on a project where I need to call a function AFTER the route has finished loading. However, when using the 'watch' functionality, it only loads on route change, but does so before route has finished loading. So when I attempt to run a script that targets DOM elements on the page, those elements don't exist yet. Is there any functionality in Vue Router that would allow me to wait until everything is rendered before running the script?
const app = new Vue({
el: '#app',
router,
watch: {
'$route': function (from, to) {
function SOMEFUNCTION()
}
},
data: {
some data
},
template: `
<router-view/>
`
})
In my opinion on this situation, you should use component life cycle method of the loaded component, either use mounted method or created method.
or if your script doesn't depend on any vue component (store) you can use router.afterEach hook
router.afterEach((to, from) => { if (to.name !== 'ROUTENAME'){ // do something }});
You should use Vue.nextTick
In your case this would translate to:
const app = new Vue({
el: '#app',
router,
watch: {
$route() {
this.$nextTick(this.routeLoaded);
}
},
data() {
return {};
},
methods: {
routeLoaded() {
//Dom for the current route is loaded
}
},
mounted() {
/* The route will not be ready in the mounted hook if it's component is async
so we use $router.onReady to make sure it is.
it will fire right away if the router was already loaded, so catches all the cases.
Just understand that the watcher will also trigger in the case of an async component on mount
because the $route will change and the function will be called twice in this case,
it can easily be worked around with a local variable if necessary
*/
this.$router.onReady(() => this.routeLoaded());
},
template: `<router-view/>`
})
This will call the routeLoaded method every time the route changes (which I'm deducing is what you need since you are using the <router-view>
element), if you also want to call it initially, I would recommend the mounted hook (like in the example) or the immediate flag on the watcher
The solution for me was to set up a custom event in every page's mounted()
hook with a mixin and listen for that event on the body
for example. If you wanted to strictly tie it with the router's afterEach
or the route watcher to ensure the route has indeed changed before the event was fired, you could probably set up a Promise
in the afterEach
and resolve it in the page's mounted()
by either the event or sharing the resolve
function through the window
.
An example:
// Component.vue
watch: {
'$route': function (from, to) {
new Promise((resolve) => {
window.resolveRouteChange = resolve;
}).then(() => {
// route changed and page DOM mounted!
});
}
}
// PageComponent.vue
mounted() {
if(window.resolveRouteChange) {
window.resolveRouteChange();
window.resolveRouteChange = null;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With