Feralheart
Feralheart

Reputation: 1920

Vue-router: Using component method within the router

My first Vue project and I want to run a loading effect on every router call. I made a Loading component:

<template>
    <b-loading :is-full-page="isFullPage" :active.sync="isLoading" :can-cancel="true"></b-loading>
</template>

<script>
    export default {
        data() {
            return {
                isLoading: false,
                isFullPage: true
            }
        },
        methods: {
            openLoading() {
                this.isLoading = true
                setTimeout(() => {
                    this.isLoading = false
                }, 10 * 1000)
            }
        }
    }
</script>

And I wanted to place inside the router like this:

router.beforeEach((to, from, next) => {
    if (to.name) {
        Loading.openLoading()
    }
    next()
}

But I got this error:

TypeError: "_components_includes_Loading__WEBPACK_IMPORTED_MODULE_9__.default.openLoading is not a function"

What should I do?

Upvotes: 0

Views: 1231

Answers (2)

Abdelillah Aissani
Abdelillah Aissani

Reputation: 3108

I don't think you can access a component method inside a navigation guard (beforeEach) i would suggest using Vuex which is a vue plugin for data management and then making isLoading a global variable so before each route navigation you would do the same ... here is how you can do it :

Of course you need to install Vuex first with npm i vuex ... after that :

on your main file where you are initializing your Vue instance :

import Vue from 'vue'
import Vuex from 'vue'

Vue.use(Vuex)

const store = new Vuex.Store({
  state: {
    isLoading: false,
  },
  mutations: {
    openLoading(state) {
      state.isLoading = true
      setTimeout(() => {
        state.isLoading = false
      }, 10000)
    },
  },
})
// if your router is on a separated file just export the store and import it there
const router = new VueRouter({
  routes: [
    {
      // ...
    },
  ],
})

router.beforeEach((to, from, next) => {
  if (to.name) {
    store.commit('openLoading')
  }
  next()
})

new Vue({
   /// ....
   router,
   store,
})

In your component:

<b-loading :is-full-page="isFullPage" :active.sync="$store.state.isLoading" :can-cancel="true"></b-loading>

Upvotes: 0

Andrew Vasylchuk
Andrew Vasylchuk

Reputation: 4779

Vuex is a good point. But for simplicity you can watch $route in your component, and show your loader when the $route changed, like this:

...
watch: {
  '$route'() {
     this.openLoading()
   },
},
...

I think it's fast and short solution.

Upvotes: 2

Related Questions