5

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?

3
  • I don't think you can do this in beforeRouteEnter hook. As it's said in the doc, does NOT have access to this` component instance. How about changing the hook to created`? Commented Nov 21, 2016 at 9:01
  • @kxxoling Typo. The object is set in a callback in the beforeEnterRoute function. I've edited the post. Commented Nov 21, 2016 at 10:33
  • Have you tried to use the hook to created instead? Commented Nov 24, 2016 at 6:14

5 Answers 5

3

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)
Sign up to request clarification or add additional context in comments.

Comments

1

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.

Comments

1

You have to use condition rendering here, which you can easily do with help of Vue directive v-if. It may give error if the data is not populated and you try to access it, so v-if will render that part of HTML only when data is present.

You need to do something like following:

<div v-if="info.order">
  <span>
    {{ info.order }}
  </span>
</div>

4 Comments

I've actually tried that. It stills throws the same errors when evaluating the properties that aren't available.
@oorst can you include your HTML.
@oorst did you forget to convert the response body string to js objects with res.json() (vue-resource api) or JSON.parse(res.body)?
Doesn't vue resource automatically return JS objects?
1

In my scenario, I had to use one Vue.set that wrapped an Object.assign:

I'm trying to set state.workouts[state.workoutDate].isDone in a Vuex mutation

    toggleWorkout(state, isDone) {
        Vue.set(
            state.workouts,
            state.workoutDate,
            Object.assign({}, state.workouts[state.workoutDate], { isDone: isDone })
        );
    },

Comments

0

Force update object setting a new object with same content

<button @click="my.object.nested.variable = 2; my = Object.assign({}, my);">

or

this.my.object.nested.variable = 2;
this.my = Object.assign({}, this.my);

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.