VueJS async component data and promises

16,969

The solution was the jsfiddle approach, with a twist. This part:

reload: function () {
      fetch('/data/api', {
        method: 'get'
      }).then(function (response) {
        return response.json();
      }).then(function (response) {
        if (response.status == "success") {
          this.records = response.payload;
        } else {
          console.error(response.message);
        }
      }).catch(function (err) {
        console.error(err);
      });
    }

needed a .bind(this) in the part which sets the this.records value after the fetch, like so:

reload: function () {
      fetch('/data/api', {
        method: 'get'
      }).then(function (response) {
        return response.json();
      }).then(function (response) {
        if (response.status == "success") {
          this.records = response.payload;
        } else {
          console.error(response.message);
        }
      }.bind(this)).catch(function (err) {
        console.error(err);
      });
    }

This post was what made it click for me.

Lesson learned: in modern JS, always keep scope in mind.

Share:
16,969

Related videos on Youtube

Swader
Author by

Swader

RMRK.app founder

Updated on September 14, 2022

Comments

  • Swader
    Swader over 1 year

    Trying out VueJS 2.0 RC, and using the fetch API to load some data for some of the components. Here's a mock example:

    const Component = {
      template: '#comp',
      name: "some-component",
      data: function () {
        return {
          basic: data.subset,
          records: function () {
            return fetch('/datasource/api', {
              method: 'get'
            }).then(function (response) {
              return response.json();
            }).then(function (response) {
              if (response.status == "success") {
                return response.payload;
              } else {
                console.error(response.message);
              }
            }).catch(function (err) {
              console.error(err);
            });
          }
        }
      }
    };
    

    The data object is a global application state, defined before the app's initialization, and only a subset of it is needed in the component, hence that part. The main set of the component's data comes from another endpoint which I'm trying to call. However, the data property expects an object, and it's getting back a Promise it can't really use in the context of a loop in the template for rendering etc (e.g. v-for="record in records")

    Am I going about this the wrong way? What's the approach to get the data records property to update once it's fully fetched? Is there a way to force the code to stop until the promise resolves (effectively making it sync)? The component is useless without the data anyway, so there's a waiting period before it can be used regardless.

    What is the right way to asynchronously populate a component's data field without using plugins like vue-async or vue-resource?

    (I know I could use the XHR/jQuery methods of non-promise ajax calls to do this, but I want to learn how to do it using fetch)


    Update: I tried defining a created hook, and a method to load the data, like this but no dice - in my own experiments, the records property fails to update once it's loaded. It doesn't change, even though the data is successfully fetched (successfully logs into console).

    Could have something to do with me using vue-router and the component I'm dealing with triggering when a link is clicked, as opposed to being a regular Vue component. Investigating further...


    Update #2: If I continue investigating the jsfiddle approach above and log this.records and response.payload to the console, it shows the records object being populated. However, this doesn't seem to trigger a change in the template or the component itself - inspecting with Vue dev tools, the records property remains an empty array. Indeed, if I add a method logstuff and a button into the template which calls it, and then have this method log this.records into the console, it logs an observer with an empty array:

    enter image description here

    Now I'm wondering why the data property of a component would be not updated even after it's explicitly set to another value. Tried setting up a watcher for $route that triggers the reload method, but no dice - every subsequent load of that route does indeed re-issue the fetch, and the console logs this.records as populated (from within fetch), but the "real" this.records remains an empty array.