I want to chain 2 resource calls together but keep it invisible from the consuming application/controller.
For example: resource "Person" has multiple "Role" records, however I want to keep "Person" and "Role" as separate resources on the server.
So the application calls the "Person" resource for a list of people but before they are returned the resource's transformReponse method calls the "Roles" resource for each person and adds the roles as an array. Therefore the application simply asks for people and gets all people with associated roles.
I've tried to simplify the scenario in the example code listed below. Here the application calls 1 resource which then calls the 2nd, however the data from the 2nd resource is resolved after the call to the initial resource in the controller returns.
Any ideas how to do this would be much appreciated.
angular.module('services', ['ngResource'])
.factory("someService2", function ($resource) {
return $resource(
'/', {}, {
get: {
method: 'GET',
transformResponse: function(data, headers){
//MESS WITH THE DATA
data = {};
data.coolThing = 'BOOM-SHAKA-LAKA-V2';
return data;
}
}
}
);
});
angular.module('services')
.factory("someService", function ($q, $resource, someService2) {
return $resource(
'/', {}, {
get: {
method: 'GET',
transformResponse: function(data, headers){
data.title1 = "Resource1";
var defer = $q.defer();
// Call 2nd resource
someService2.get(function(d){
data.title2 = d.coolThing;
defer.resolve(data);
});
return defer.promise;
}
}
}
);
});
var app = angular.module('myApp', ['ngResource', 'services']);
app.controller('MainController', ['$scope', 'someService', function ($scope, svc) {
$scope.title1 = 'Transform Test';
$scope.title2 = 'Transform Test2';
var promise = svc.get().$promise.then(function(data){
$scope.title1 = data.title1;
$scope.title2 = data.title2;
});
}]);
The HTML is very simple:
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script type="text/javascript" src="http://code.angularjs.org/1.2.0-rc.2/angular-resource.js" ></script>
<script type="text/javascript" src="JScript.js"></script>
</head>
<body>
<div ng-app="myApp">
<div ng-controller="MainController">
<h1>{{title1}}</h1>
<h1>{{title2}}</h1>
</div>
<div>
</body>
</html>
I have finally come to the conclusion that using the TransformResponse function of the Resource will not work as required as it looks like the resource does some external wrapping of the data further up the promise pipeline. ie. the TransformResponse happens before the promise is resolved internally.
My final solution was to simply abstract the resource call in my own object and chain my promises here. This still allows me to abstract the nested calls from the controller which was my main requirement.
Service2:
angular.module('services', ['ngResource'])
.factory("someService2", function ($resource) {
return $resource(
'/', {}, {
get: {
method: 'GET',
transformResponse: function(data, headers){
//MESS WITH THE DATA
data = {};
data.coolThing = 'BOOM-SHAKA-LAKA-V2';
return data;
}
}
}
);
});
Service1, which encapsulates the nested calls:
angular.module('services')
.factory("someService", function ($q, $resource, someService2) {
var r = $resource(
'/', {}, {
get: {
method: 'GET',
transformResponse: function(data, headers){
//MESS WITH THE DATA
data = {};
data.title1 = 'BOOM-SHAKA-LAKA-V1';
return data;
}
}
}
);
var svc = {
get: function(){
var data;
var defer = $q.defer();
r.get().$promise.then(
function(x){
data = x;
someService2.get().$promise.then(
function(y){
data.title2 = y.coolThing;
defer.resolve(data);
}
);
}
);
return defer.promise;
}
};
return svc;
});
Controller:
var app = angular.module('myApp', ['ngResource', 'services']);
app.controller('MainController', ['$scope', 'someService', function ($scope, svc) {
$scope.title1 = 'Transform Test';
$scope.title2 = 'Transform Test2';
svc.get().then(function(data){
$scope.title1 = data.title1;
$scope.title2 = data.title2;
});
}]);
HTML:
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script type="text/javascript" src="http://code.angularjs.org/1.2.0-rc.2/angular-resource.js" ></script>
<script type="text/javascript" src="http://localhost/Angular/NestedResources/JS.js"></script>
</head>
<body>
<div ng-app="myApp">
<div ng-controller="MainController">
<h1>{{title1}}</h1>
<h1>{{title2}}</h1>
<pre>
{{data}}
</pre>
</div>
<div>
</body>
</html>