15

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>
7
  • You should post your code. I don't think is necesary to go synchronously Commented Jun 9, 2016 at 19:09
  • @YerkoPalma I am using vue-router and vuex. currently I put code (for request an api) in App.vue at ready() Commented Jun 9, 2016 at 19:30
  • @YerkoPalma My code is like general single page app project until I meet this issue. Commented Jun 9, 2016 at 19:32
  • 1
    Just update my question Commented Jun 9, 2016 at 19:45
  • 1
    Related: stackoverflow.com/questions/37731656/… Commented Jun 9, 2016 at 19:58

3 Answers 3

14

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

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

3 Comments

Also, try to use another cycle hook instead of ready as ready is called when the DOM has been rendered, and you want that code before that event. Prefer created hook
how about if I call the authService in main.js. like: auth.getUser(null, (response) => { router.start(App, '#app') }) then in App.vue just receive the auth data using: this.authData = auth.user I just try this and work like expected. but I am not sure if this is good solution
because if I using solution that you gave. it will have many v-if="dataReady" in every routerComponent.
3

You could use the data transition hook with the waitForDataoption 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

Comments

2

You could just prevent Vue from trying to access the object property, like this:

{{ $root.authData ? $root.authData.name : null }}

You could even change null for a Loading... message in some cases.

Comments

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.