Sebastian Rush
Sebastian Rush

Reputation: 538

Vue.js cannot access to nested properties of data object

In Vue.js I fetch some data of a json-file like this:

export default {
    data () {
       return {
           data: []
       }   
    },
    created () {
        this.fetchData();    
    },
    methods: {
        fetchData () {
            $.getJSON('data/api.json', function(el) {
                this.data = el;
            }.bind(this)),
        }
    }
}

The fetched data has the following structure:

{
    time: '17:00',
    pick: {
        box: {
            single: 1,
            multi: 2
        }    
    }
}

When I try to access to {{ data.pick.box }} or {{ data.pick.box.single }} in my component, I always get this error message:

vue.js?3de6:2963 Uncaught TypeError: Cannot read property 'box' of undefined
at Proxy.render (eval at <anonymous> (app.js:126), <anonymous>:4:46)
at VueComponent.Vue._render (eval at <anonymous> (app.js:139), <anonymous>:2954:22)
at VueComponent.eval (eval at <anonymous> (app.js:139), <anonymous>:2191:21)
at Watcher.get (eval at <anonymous> (app.js:139), <anonymous>:1656:27)
at new Watcher (eval at <anonymous> (app.js:139), <anonymous>:1648:12)
at VueComponent.Vue._mount (eval at <anonymous> (app.js:139), <anonymous>:2190:19)
at VueComponent.Vue$3.$mount (eval at <anonymous> (app.js:139), <anonymous>:5978:15)
at VueComponent.Vue$3.$mount (eval at <anonymous> (app.js:139), <anonymous>:8305:16)
at init (eval at <anonymous> (app.js:139), <anonymous>:2502:11)
at createComponent (eval at <anonymous> (app.js:139), <anonymous>:4052:9)

Is there any restriction for accessing deep nested objects? When I call {{ data }}, for example, I get the whole data structure displayed as a string correctly.

As mentioned by Nora, here is the fiddle: jsfiddle

Upvotes: 11

Views: 6052

Answers (3)

Saurabh
Saurabh

Reputation: 73609

You are getting this error, as the data is not populated while it is being loaded, and you get error in that while. You can use v-if in your template till the data is populated in the view. So the element will not be rendered till the data is loading and once the data is loaded it will show the data.

It can be like following:

<div v-if="data.pick">
  {{data.pick.box}}
</div>

Upvotes: 8

Tax Raoul
Tax Raoul

Reputation: 73

My solution was to create an empty object with empty properties.

 data () {
       return {
           loading: false,
           data: {pick:{},}
       }   
    },

Upvotes: 1

Nora
Nora

Reputation: 3261

You can try waiting for data to finish loading to display it in your template:

export default {
    data () {
       return {
           loading: false,
           data: []
       }   
    },
    created () {
        this.fetchData();    
    },
    methods: {
        fetchData () {
            this.loading = true;
            $.getJSON('data/api.json', function(el) {
                this.data = el;
                this.loading = false;
            }.bind(this)),
        }
    }
}

In template:

<template>
  <div v-if="!loading">
    {{ data.pick.box }}
  </div>
</template>

Upvotes: 10

Related Questions