I really like the clean (and I think easy to follow) way that promises were autounwrapped:
$scope.myData = DataService.query({something:"etc"}); // done;
And I really don't care for what seems to be the standard way of doing it now, without the automatic unwrapping:
DataService.query({something:"etc"}).$promise.then(function (data){
$scope.myData = data;
});
What I'd like to see is something like this:
$scope.pulseData = $scope.setPromise(CitsciAnalytics.pulse({
projId:"yardmap"
}));
But I can't see how to make that happen. The closest I got was:
$scope.pulseData = $scope.setPromise("pulseData", CitsciAnalytics.pulse({
projId:"yardmap"
}));
Using a function added to the root scope:
.run(["$rootScope", "$log", function ($rootScope, $log) {
//parent method to avoid promise unwrapping boilerplate
$rootScope.setPromise = function (scopeVar, promise) {
if (arguments.length === 2 && promise && promise.$promise) {
var scope = this;
promise.$promise.then(function (data){
scope[scopeVar] = data;
});
} else {
$log.error("$rootScope.setPromise has invalid arguments");
}
};
}]);
but I don't like the unDRY requirement of having to pass the scope variable name as an additional string. Has anyone else tackled this, or see a way to do this more cleanly?
First of all you don't need to use
DataService.query({something:"etc"}).$promise.then(function(data){
$scope.myData = data;
});
which clearly refers to a $resource
, because $resource
will return an empty array or object and fill it with data as they arrive.
So, with a $resource
class, you can still use
$scope.myData = DetaService.query(...);
$resource
's paradigm is also a good approach to follow in your own "data-fetching" services: Return and empty array and fill it with data as they arrive.
E.g.:
.factory('DataService', function ($http) {
function query(params) {
var data = [];
$http.get('/some/url/with/params').then(function (response) {
response.data.forEach(function (item) {
data.push(item);
});
});
return data;
}
return {
query: query
};
});
.controller('someCtrl', function ($scope, DataService) {
$scope.data = DataService.query({...});
If you have to use thrid-party services that return a promise, you can implement your generic function to offer similar functionality:
.run(function ($rootScope) {
$rootScope.promiseToArray = function (promise) {
var arr = [];
promise.then(function (data) {
data.forEach(function (item) {
arr.push(item);
});
});
return arr;
};
});
.controller('someCtrl', function ($scope, ThirdPartyService) {
$scope.data = $scope.promiseToArray(ThirdPartyService.fetchData());
});
See, also, this short demo.
The above samples are just for illustration purposes and not production-ready code.
I a real-world app, you would need to gracefully handle exceptions, rejections etc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With