I really don't like the fact that, because of the "promise" way of doing things, the consumer of the service that uses $http has to "know" about how to unpack the response.
I just want to call something and get the data out, similar to the old $scope.items = Data.getData();
way, which is now deprecated.
I tried for a while and didn't come up with a perfect solution, but here's my best shot (Plunker). It may be useful to someone.
app.factory('myService', function($http) {
var _data; // cache data rather than promise
var myService = {};
myService.getData = function(obj) {
if(!_data) {
$http.get('test.json').then(function(result){
_data = result.data;
console.log(_data); // prove that it executes once
angular.extend(obj, _data);
});
} else {
angular.extend(obj, _data);
}
};
return myService;
});
Then controller:
app.controller('MainCtrl', function( myService,$scope) {
$scope.clearData = function() {
$scope.data = Object.create(null);
};
$scope.getData = function() {
$scope.clearData(); // also important: need to prepare input to getData as an object
myService.getData($scope.data); // **important bit** pass in object you want to augment
};
});
Flaws I can already spot are
- You have to pass in the object which you want the data added to, which isn't an intuitive or common pattern in Angular
getData
can only accept the obj
parameter in the form of an object (although it could also accept an array), which won't be a problem for many applications, but it's a sore limitation
- You have to prepare the input object
$scope.data
with = {}
to make it an object (essentially what $scope.clearData()
does above), or = []
for an array, or it won't work (we're already having to assume something about what data is coming). I tried to do this preparation step IN getData
, but no luck.
Nevertheless, it provides a pattern which removes controller "promise unwrap" boilerplate, and might be useful in cases when you want to use certain data obtained from $http in more than one place while keeping it DRY.