Svedr
Svedr

Reputation: 579

Set object in data from a method in VUE.js

I have been stuck with this issues for 2 hours now and I really can't seem to get it work.

const app = new Vue({
  el: '#book-search',
  data: {
    searchInput: 'a',
    books: {},
  },
  methods: {
    foo: function () {
      axios.get('https://www.googleapis.com/books/v1/volumes', {
        params: {
          q: this.searchInput
        }
      })
      .then(function (response) {
        var items = response.data.items
        for (i = 0; i < items.length; i++) {

          var item = items[i].volumeInfo;

          Vue.set(this.books[i], 'title', item.title);   

        }
      })
      .catch(function (error) {
        console.log(error);
      });

    }
  }
});

When I initiate search and the API call I want the values to be passed to data so the final structure looks similar to the one below.

data: {
  searchInput: '',
  books: {
    "0": {
       title: "Book 1"
     },
    "1": {
       title: "Book 2"
     }
},

Currently I get Cannot read property '0' of undefined.

Upvotes: 8

Views: 44376

Answers (3)

badunius
badunius

Reputation: 71

// update component's data with some object's fields
// bad idea, use at your own risk

Object
  .keys(patch)
  .forEach(key => this.$data[key] = patch[key])

Upvotes: 1

Mykola Riabchenko
Mykola Riabchenko

Reputation: 628

yep, the problem is about context. "this" returns not what you expect it to return.

  1. you can use

    let self = this;

  2. or you can use bind

    function(){this.method}.bind(this);

the second method is better.

Also google something like "how to define context in js", "bind call apply js" - it will help you to understand what is going wrong.

Upvotes: 2

abhishekkannojia
abhishekkannojia

Reputation: 2856

Problem lies here:

Vue.set(this.books[i], 'title', item.title);

You are inside the callback context and the value of this is not the Vue object as you might expect it to be. One way to solve this is to save the value of this beforehand and use it in the callback function.

Also instead of using Vue.set(), try updating the books object directly.

const app = new Vue({
  el: '#book-search',
  data: {
    searchInput: 'a',
    books: {},
  },
  methods: {
    foo: function () {
      var self = this;
      //--^^^^^^^^^^^^ Save this
      axios.get('https://www.googleapis.com/books/v1/volumes', {
        params: {
          q: self.searchInput
          //-^^^^--- use self instead of this
        }
      })
      .then(function (response) {
        var items = response.data.items
        var books = {};
        for (i = 0; i < items.length; i++) {

          var item = items[i].volumeInfo;
          books[i] = { 'title' : item.title };
        }
        self.books = books;
      })
      .catch(function (error) {
        console.log(error);
      });

    }
  }
});

Or if you want to use Vue.set() then use this:

Vue.set(self.books, i, {
     'title': item.title
});

Hope this helps.

Upvotes: 15

Related Questions