4

I'm trying to init an empty array in the data and then get a JSON from the server and populate it.

The problem is that the array always have an extra Observer object so when i log it i see this:

empty items array: [ob: Observer]

here is a code excerpt:

data() {
        return {
            items: []
        }
    },
 created() {
         this.$http.get('/api/menus').then(function (response) {

            console.log('items before', this.items); //THIS LOGS items before: [__ob__: Observer]
             this.items = [].concat(response.body);
            this.items.forEach(function (item) {
              console.log('item', item);

              item.$add('active', false);

              item.tests.forEach(function (test) {
                  test.$add('active', false);
              });
        });

         }).catch(function (err) {
             console.error('err', err);

         });

     },

The problem is that when trying to add a new property to the objects in the array i get an error:

err TypeError: item.$add is not a function

when i debug i see it happens because it considers the observer object as part of the array.

Is it normal? should i just check if $add exists? what about when rendering it in the view, does Vue ignore this object?

8
  • I think this is normal, because VueJS use observers for reactivity, so each item in data object has attached observer.Check this but with Browser Console, not using the JsBin jsbin.com/qusugoyame/edit?html,js,console,output Commented Mar 24, 2017 at 9:44
  • Yes, all correct, and what is the problem though? Commented Mar 24, 2017 at 9:54
  • What should be $add method ? It depracated use $set Commented Mar 24, 2017 at 10:17
  • 1
    Here is the working example jsbin.com/qusugoyame/edit?html,js,console,output - let me know are you looking for this so I can explain it and add as answer Commented Mar 24, 2017 at 10:51
  • 1
    Yeah using arrow function sometimes could solve context issue depending on situation.@GONG provided good answer so you can accept it, there are no need to post mine one. Commented Mar 24, 2017 at 11:07

1 Answer 1

5

According to your code, you want to set active property in your items object to false. Also you want to set all the properties active in every item's tests property to false.

Vue.js is reactive and detect changes automatically, but only for objects themselves, not their properties. For array vue will only detect changes by those methods (more about list rendering in vue.js https://v2.vuejs.org/v2/guide/list.html#ad):

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

But how about properties? You can force vue to see change in deep of array or object with Vue.set(object, property, value) or this.$set in any Vue instance.

So, in your example you can implement it like this:

this.items.forEach(function (item, key) {
    console.log('item', item);

    this.$set(this.items[key], 'active', false);

    item.tests.forEach(function (test, testKey) {
        this.$set(this.items[key].tests[testKey], 'active', false);
    }, this);
}, this);

And it should work. Here is working example: http://jsbin.com/cegafiqeyi/edit?html,js,output (some ES6 features used, don't be confused)

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

2 Comments

This way your losing this context. Editing.
@JonatasWalker oh, yes, sorry, it's all ES6

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.