VueJS async component data and promises
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.
Related videos on Youtube
Comments
-
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, thedata
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
andresponse.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 methodlogstuff
and a button into the template which calls it, and then have this method logthis.records
into the console, it logs an observer with an empty array: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 thereload
method, but no dice - every subsequent load of that route does indeed re-issue the fetch, and the console logsthis.records
as populated (from within fetch), but the "real"this.records
remains an empty array.