ember-concurrency
ember-concurrency copied to clipboard
Polling a model with ember-concurrency
hi! i want to make a request to update my vehicles list every 10 seconds to have updated values. As i read on this post(under fig 4) this can be done with ember-concurrency from a route model hook. I just want to simulate this behavior:
For pages where the data is likely to change a lot, like our filters interface, we store two task instances in our model, one for the current data request, and one for the last performed data request for this same model. With these two task instances, we can display stored data while we update the model with new data, rather than always showing an obstructive loading indicator.
My route looks like:
import Ember from 'ember'
import { task } from 'ember-concurrency'
export default Ember.Route.extend({
model() {
return {
vehicles: this.get('findVehiclesTask').perform(), // TODO: refresh request every 10 sec
groups: this.get('findGroupsTask').perform(),
geofences: this.get('findGeofencesTask').perform(),
}
},
findVehiclesTask: task(function* () {
return yield this.store.findAll('vehicle')
}),
findGroupsTask: task(function* () {
return yield this.store.findAll('group')
}),
findGeofencesTask: task(function* () {
return yield this.store.findAll('geofence')
}),
});
Any suggestion about how to do that? Thank you!
findVehiclesTask: task(function * () {
while (true) {
yield timeout(POLLING_TIMEOUT);
return this.store.findAll('vehicle');
}
}).cancelOn('deactivate')
There is a difference between a Task
and TaskInstance
. task
is returning a Task
, and when you run perform()
on a task it returns a TaskInstance
, so to get the last successful task, you can do this.myTask.lastSuccessful
which you can use for the last result.
model() {
return {
findVehichlesTask: this.findVehiclesTask
...
};
}
{{ model.findVehichlesTask.lastSuccessful.value }}
@mupkoo I have the same task in regards to polling a model but using findRecord instead of findAll with a dynamic id. In my case, I will have to call perform to pass in the id but in doing so I would lose the ability to continue to poll for more data because I would be returning a TaskInstance instead of a Task. How would I go about doing it with a dynamic id?
model(params) {
return {
checkIfResultFinishedTask: this.checkIfResultFinished.perform(params.result_id)
...
};
}
checkIfResultFinished: task(function * (resultId) {
while (true) {
yield timeout(POLLING_TIMEOUT);
return this.store.findRecord('result', resultId);
}
}).cancelOn('deactivate')
{{ model.checkIfResultFinished.lastSuccessful.value }}
Would it work if I did the polling in the controller instead using a computed prop? I also want to be able to cancel the task if transitioning and if a certain condition is met.
Result-Controller.js
import Controller from '@ember/controller';
import { task } from "ember-concurrency"
import { computed } from "@ember/object"
export default Controller.extend({
fetchResult: computed("model.resultId", function() {
return this.get("fetchResultTask").peform(this.get("model").resultId)
})
fetchResultTask: task(function*(resultId){
const result = this.get("store").peekRecord("result", resultId)
if(result && result.status === "COMPLETED") {
return result
}
yield timeout(1000);
return this.get("store").findRecord("result", resultId)
})
});
result.hbs
{{ fetchResult.lastSuccessful.value }}
@LuisAverhoff i have made the polling to start from route on setupcontroller hook and the first one request in model
model: function (params) {
return Ember.RSVP.hash({
groups: this.store.findAll("group"),
vehicles: this.store.findAll("vehicle"),
selectedVehicle: this.store.findRecord("vehicle", params.vehicle_id),
routes: this.store.query("route", {
$where: {
vehicle_id: params.vehicle_id,
'>=': {
start_time: params.routeStartDate
},
'<=': {
start_time: params.routeEndDate
}
}
}),
stops: stops,
geofences: this.store.findAll('geofence')
})
},
setupController() {
this._super(...arguments)
this.get('pollServerForChanges').perform()
},
pollServerForChanges: task(function* () {
// eslint-disable-next-line no-constant-condition
while (true) {
yield timeout(10000)
yield this.store.query('vehicle', { geolocation: true })
}
}).cancelOn('deactivate').restartable(),
In one component i start the polling directly on init hook, and i have two different tasks:
init() {
this._super(...arguments)
this.get('pollData').perform()
},
getData: task(function* () {
let api = this.get('api')
return yield api.request('/dashboard/home/vehicle-status', {
contentType: 'application/json; charset=utf-8',
dataType: 'json',
}).then(res => {
if (res.data) {
return this.formatData(res.data)
}
})
}).drop(),
pollData: task(function* () {
while (true) {
yield this.get('getData').perform()
yield timeout(10000)
}
}).drop(),