0

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?

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

9 Comments

I placed watch in the component, but nothing happened
Does this watch method invoke? Can you put console.log() in it?
You component should alway be render in DOM (don't apply v-if) on it.
I replaced the component to the main componed and now it works 'til infinity. How can I watch if in the background everything is loaded?
What do you mean by everything is loaded? When does this event happen?
|
0

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>

3 Comments

Using Vuex is a good point. But you answer has an error in this line :active.sync="$store.state.isLoading". You will get Vuex warn because you can't mutate store directly, is suggest you to rewrite it using getter and setter.
Hi thanks but im not mutating the value there its just bidden ( not ´v-model´) and yes using a getter is better ofc .... Your solution is much better i guess you just need to include the condition that he is implemeting
Potentially, he is modifying it directly in component, because he added .sync modifier, which allows props changing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.