Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deeply nested data objects in VueJS

Tags:

vue.js

I've got a VueJs front end that fetches some data from an API. The app uses vue-router.

The data fetched for one component is similar to the following:

{
  name: ...,
  email: ...,
  order: {
    data: {
      line_items: [
        {
          quantity: ...
        }
      ]
    }
  }
}

The component is instantiated with a data object called info:

data () {
  return {
    info: {}
  }
}

In the beforeRouteEnter hook, the data is fetched by a vue-resource http.get and info is set to the body of the result like this:

vm.info = result.body 

When the component renders, the following errors are produced:

TypeError: undefined is not an object (evaluating _vm.order.data.line_items')

In the template, the data is referenced in curly braces as per usual, however, if I just reference info in the template like this:

{{ info }}

it will output all of the data and not complain at all.

What is the correct way to assign a deeply nested data object?

like image 697
oorst Avatar asked Nov 21 '16 06:11

oorst


2 Answers

If you are finding @saurabh answer is not working then you may need to check how you are assigning the new values to your object.

Firstly is the data being accidiently set as a string? hence {{ info }} working (or appearing to). May be worth using response.json() to set the data.

If thats not it then the error may be produced as the data you have set is not reactive. As you are assigning a nested object you may need to use different methods to make it reactive, i.e

Vue.set(vm.someObject, 'b', 2)

or

this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })

check out: https://v2.vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats

because your response is an object you may want to break out your data into corresponding params, i.e.

data () {
  return {
    info: {
      name: '',
      email: '',
      order: {},
    },
  }
}

then you can assign name & email as you expected (info.email = ...).

For info.order you'd use Vue.set:

Vue.set(this.info, 'order', result.body.order)
like image 62
GuyC Avatar answered Sep 30 '22 04:09

GuyC


The actual issue here is a life cycle one. The route guard beforeRouteEnter is called after the component is created so the error is thrown because the data isn’t there when the component tries to access it.

like image 41
oorst Avatar answered Sep 30 '22 04:09

oorst