Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue Router - call function after route has loaded

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/>
  `
})
like image 641
RJ McLain Avatar asked Sep 23 '18 16:09

RJ McLain


3 Answers

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 }});

like image 163
feisalramar Avatar answered Nov 04 '22 16:11

feisalramar


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

like image 24
Tofandel Avatar answered Nov 04 '22 14:11

Tofandel


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;
      }
    }

like image 1
Arnošt Neurad Avatar answered Nov 04 '22 15:11

Arnošt Neurad