10

OK. I'm not a total newbie and do have some Vue xp but this is bugging me. What really obvious thing am I missing.

I have an object loaded via an ajax call inside a mounted method:

job: {
  "title": "value",  
  "location": {
    "name":"HONG KONG"
  }
}

When I call {{ job.title }} all good. When I call {{ job.location.name }} I have an undefined error but the value renders. When I call {{ job.location }} I get the json object so it is defined.

Aaargh! I'm sure it's really simple but can't possibly see why this isn't as straight forward as it should be.

// Additional

This is my entire Vue class

    const router = new VueRouter({
        mode: 'history',
        routes: []
    });
    const app = new Vue( {
      router,
      el: '#app',
      data: {
        job: {}
      },
      mounted: function () {
        var vm = this
        jQuery.ajax({
            url: 'https://xxx' + this.jobId,
            method: 'GET',
            success: function (data) {
                vm.job = data;
            },
            error: function (error) {
                console.log(error);
            }
        });
      },
      computed: {
        jobId: function() {
            return this.$route.query.gh_jid
        }
      }
    })
4
  • Everything is alright in this snippet you provided. The error should be somewhere else. Provide more code Commented Oct 16, 2018 at 9:05
  • Are you define 'job.location.name' in your vue Instance of data ? I'm not sure is it that error is appeared before your ajax request, so provide more code Commented Oct 16, 2018 at 9:19
  • I've added some more code. As you can see I have defined "job" as an empty object which I've done as standard loads of times. Thanks Commented Oct 16, 2018 at 9:32
  • try using vm.$set(job, data) instead of vm.job = data; Commented Oct 16, 2018 at 9:39

2 Answers 2

14

When your component renders it tries to get value from job.location.name but location is undefined before ajax request is completed. So I guess error is kind of Cannot read property 'name' of undefined.

To fix this you can define computed property locationName and return, for example, empty string when there is no loaded job object yet:

computed:{
//...
    locationName() {
       return this.job.location ? this.job.location.name : '';
    }
}

Or you can define computed for location and return empty object if there is no location, or you can just add empty location object to your initial data(if you are sure that your API response always has location) like job: { location: {}} all ways will fix your issue.

Also there is a way to fix it with v-if directive in your template:

<div v-if="job.location">
   {{ job.location.name }}
   <!-- other location related stuff -->
</div>
Sign up to request clarification or add additional context in comments.

5 Comments

Thanks for the response. I understand the logic of the answer but it doesn't account for job.title being available and rendering without issue.
@Dr.ifle title works because it's property of job object that exists always and job.title just returns undefined if there is no title prop without any error. Your location is nested object and error is related to location object properties.
Thanks. That does make sense and indeed works. On the whole I guess it would be nice to have some way of not rendering until the data was mounted.
Yeah, you can avoid rendering body of your component with v-if="job" as well and define job: null in data, so you can safely use all properties within conditional block inside template...but if you will have some logic in component related to properties of nested objects you still have to do some null checking in code.
Nombre: <strong>{{ empleado?.nombre }}</strong> and how can i do this
0

An ES6 solution for you:

computed: {
  getJobName(){
    return this.job?.location.name
  }
}

Optional Chaining

2 Comments

Nombre: <strong>{{ empleado?.nombre }}</strong> and how can i do this
@juancarlospeñacabrera You can only do that if you are using Vue3. Or, turn that into a computed property and do the optional chaining in the <script> tag.

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.