8

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.

5
  • Value of this is different in the callback function of axios .then() method. You have to save the value of this outside before using it in callback scope. Commented Jul 2, 2017 at 9:26
  • @abhishekkannojia If I change this to app, that is how my Vue instance is defined, it throws a Cannot convert undefined or null to object error. Commented Jul 2, 2017 at 9:29
  • Possible duplicate of Axios can't set data Commented Jul 2, 2017 at 10:20
  • Notice that this is about a "traditional" JavaScript object (dictionary), not an actual Set object as created with new Set() - I came here looking how Vue handles these... Commented Aug 5, 2019 at 15:22
  • two hours for real. Sigh. Commented Sep 2, 2022 at 17:50

3 Answers 3

15

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.

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

1 Comment

Hey, thanks for your help, this makes a lot of sense, but I am still getting the Cannot convert undefined or null to object error.
2

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.

Comments

1
// 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])

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.