I have single page application that requires authentication. When user was authenticated then visit some pages or hit reload button in browser it will request an api that provide their auth data. then I have an error like this:
[Vue warn]: Error when evaluating expression "auth.name": TypeError: Cannot read property 'name' of null (found in component: <navbar>)
This error is caused because vue render auth data while the request to api have not finished yet.
Is possible to make vue wait the request api until finish first, before vue render auth data?
just more clearly what going on here. Here is the code:
// main.js
import Vue from 'vue'
import App from './App.vue' // root vue
import store from './vuex/store' // vuex
import router from './router' // my router map
sync(store, router)
router.start(App, '#app')
// end main.js
// App.vue
<template>
<main>
<div class="wrapper">
<router-view></router-view>
</div>
</main>
</template>
<script>
import authService from './services/auth' // import authservice
ready () {
// here is code that should be done first before vue render all authData
auth.getUser((response) => {
self.authData = response
})
},
data () {
return {
authData: null // default is null until the api finish the process
}
}
</script>
// end App.vue
// SomeRouterComponents.vue
<template>
<!-- some content -->
<div>
// always got error: cannot read property 'name' of null
// here I expect to render this after api has been resolved
{{ $root.authData.name }}
</div>
<!-- some content -->
</template>
The problem as you said is that you try to access an object that isn't present, and because of the error, Vue can't render it in the next tick. The solution is to use a simple v-if
to check if the data is loaded, this work only for reactive data.
root component
import auth from './services/auth' // import authservice
ready () {
// here is code that should be done first before vue render all authData
auth.getUser((response) => {
self.authData = response
self.dataReady = true
})
},
data () {
return {
authData: null, // default is null until the api finish the process
dataReady: false
}
}
otherComponent
<div v-if="dataReady">
// note that if you use v-show you will get the same error
{{ $root.authData.name }}
</div>
<div v-if="!dataReady">
// or some other loading effect
Loading...
</div>
I used v-if="!dataReady"
instead of v-else
because it will be deprecated in Vue 2.0
You could use the data transition hook
with the waitForData
option enabled:
<script>
import authService from './services/auth'
export default {
route: {
waitForData: true, // wait until data is loaded
data (transition) {
authService.getUser((response) => {
transition.next({ authData: response }) // set data
})
}
},
data () {
return {
authData: null
}
}
}
</script>
Also, if you don't want to use that option, you could check if the data is loaded by using the $loadingRouteData
property.
More details here: http://router.vuejs.org/en/pipeline/data.html
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