I have build a simple service that makes multiple requests. The service has two methods. I cannot call one method from another inside the service.
Plunkr: http://plnkr.co/edit/2fERik4uTxbxlVOhncMd?p=preview
app.factory('Report', ['$http', function($http){
var Authors = {
reports : [],
requests :[{'url':'data/data.cfm','response':'first'},
{'url':'data.json','response':'second'},
{'url':'data.json','response':'third'},
{'url':'data.json','response':'forth'}],
getReport : function(target, source, response, callback) {
return $http({ url:source,
method:"POST",
params:{url : target}
}).success(function(result) {
$scope.progress = response;
angular.extend($scope.user, result)
console.log($scope.user)
}
).error(function(error){
$scope.progress = response
})
},
startQueue : function (target) {
var promises = [];
this.requests.forEach(function (obj, i) {
console.log(obj.url)
promises.push(getReport(target, obj.url, obj.response, function(value){
reports.push(value);
console.log(value)
}));
});
$q.all(promises).then(function () {
console.log("Finito");
},function(error){
console.log("errori")
});
}
};
return Authors;
}])
When I try to call getReport from inside startQueue I get error: getReport is not defined.
Change your factory to:
app.factory('Report', ['$http', function($http){
var Authors = {
reports : [],
requests :[{'url':'data/data.cfm','response':'first'},
{'url':'data.json','response':'second'},
{'url':'data.json','response':'third'},
{'url':'data.json','response':'forth'}],
};
Authors.getReport = function(target, source, response, callback) {
};
Authors.startQueue = function (target) {
};
return Authors;
}])
I know this is 'really late', but it looks like it's because you don't have $q injected.
Change:
app.factory('Report', ['$http', function($http){
to
app.factory('Report', ['$http','$q', function($http,$q){
Related
I have this array I am getting through the following method:
var url= *url defined here*;
$scope.ViewProfile = function () {
$http.get(url)
.success(function (response) {
$scope.ProfileList = response;
$scope.FavNumbers = $scope.ProfileList[0].FavNumbers;
})
.error(function () {
});
}
I am required to edit the Fav Numbers list on the UI. and post it back to another url through http post url method. What I am stuck is with the concept of asynchronous calls, due to which I am unable to retrieve the favorite numbers list to be available for editing. Please help!
I have tried a method of using promises as follows:
app.factory('myService', function($http) {
var myService = {
async: function(url) {
var promise = $http.get(url).then(function (response) {
console.log(response);
return response.data;
});
// Return the promise to the controller
return promise;
}
};
return myService;
});
In my controller I am doing:
angular.module('JuryApp').controller('mycontroller', ['myService', function (myService) {
myService.async(url).then(function(d) {
$scope.data = d;
});
app.controller('MainCtrl', function( myService,$scope) {
// Call the async method and then do stuff with what is returned inside our own then function
myService.async().then(function(d) {
$scope.data = d;
});
});
But I keep getting the error 'd is not defined'. It keeps giving an error of some sort, where the debugger goes into an infinite loop or something.
You are overcomplicating it, I think. Async calls are actually pretty simple:
You're service:
app.factory("myService", ["$http", function($http) {
var MyService = {
getData: function(url) {
return $http.get(url); //$http returns a promise by default
}
};
return MyService;
})];
Your controller:
angular.module('JuryApp').controller('mycontroller', ['myService', function (myService) {
$scope.FavNumbers = [];
var url = "http://my.api.com/";
myService.getData(url).then(function(response) {
$scope.FavNumbers = response.data[0].FavNumbers;
});
}]);
That's all that you need to do.
I am creating one sample application, where I have API call for getting classes say
http://localhost:8080/school/4/classes
I have created a service for this
appServices.service( 'classService', ['$http', '$q',
function($http,$q){
this.getClass = function() {
var classes = $q.defer()
$http.get( "http://localhost:8080/school/4/classes" )
.then(function(data) {
classes.resolve(data)
});
return classes.promise
}
}])
I have two controllers say ctrl1 and ctrl2, in both I have code for service as
classService.getClass().then(function(data) {
$scope.classList = data.data.classes
})
My problem is two time api call is happening, can we reduced many api calls to one because my data is not going to be changed. I have already tried with { cache: true } but no luck
Thanks
The simplest way to prevent multiple calls is to use cache option:
app.service('classService', ['$http', function($http) {
this.getClass = function() {
return $http.get('data.json', { cache: true }).then(function(response) {
return response.data;
});
};
}])
Note, that you should not use $q as it's redundant.
In case if you need more control over the cache you can store reference to resolved promise:
app.service('classService', ['$http', function($http) {
var promise
this.getClass = function() {
if (!promise) {
promise = $http.get('data.json').then(function(response) {
return response.data;
});
}
return promise
};
}]);
And one more pattern with the most flexibility:
app.service('classService', ['$http', '$q', function($http, $q) {
var data;
this.getClass = function() {
return data ? $q.when(data) : $http.get('data.json').then(function(response) {
data = response.data;
return data;
});
};
}])
Have this scenario when I make a request via $http in the first service, and then I want to manipulate the data in other service. For some reassons my returned object is empty. Any advice ?
.factory('widgetRestService',['$http','$log',function($http,$log){
var serviceInstance = {};
serviceInstance.getInfo = function(){
var request = $http({method: 'GET', url: '/rest/widgets/getListInfoDashboards'})
.then(function(success){
serviceInstance.widgets = success.data;
$log.debug('serviceInstance.widgets SUCCESS',serviceInstance.widgets);
},function(error){
$log.debug('Error ', error);
$log.debug('serviceInstance.widgets ERROR',serviceInstance.widgets);
});
return request;
};
serviceInstance.getAllWidgets = function () {
if (serviceInstance.widgets) {
return serviceInstance.widgets;
} else {
return [];
}
};
return serviceInstance;
}])
.factory('OtherService',['widgetRestService','$log', function(widgetRestService, $log){
widgetRestService.getInfo();
// and now I want to return widgetRestService.widgets [{things},{things},{things}]
return widgetRestService.getAllWidgets(); // returns []
}])
Result: [ ]
You must wait for your HTTP request to complete before trying to access the data that it returns. You can do this by accessing getAllWidgets within a then attached to the Promise returned by getInfo.
.factory('OtherService', ['widgetRestService','$log', function(widgetRestService, $log) {
return widgetRestService.getInfo().then(function () {
return widgetRestService.getAllWidgets();
});
}])
Consume OtherService somewhere:
OtherService.then(function (widgets) {
// do something with `widgets`...
});
It seems you have to return promise instead of response to get the data from another service.
serviceInstance.getInfo = function(){
var deferred = $q.defer();
$http({method: 'GET', url: '/rest/widgets/getListInfoDashboards'})
.then(function(success){
deferred.resolve(success.data);
},function(error){
$log.debug('Error ', error);
$log.debug('serviceInstance.widgets ERROR',serviceInstance.widgets);
});
return deferred.promise;
};
widgetRestService.getInfo() is returning a promise, so you have to wait for its resolution:
.factory("OtherService", ["widgetRestService", "$log", "$q"
function (widgetRestService, $log, $q) {
var deferred = $q.defer();
widgetRestService.getInfo().then(function () {
// only here, you're sure `serviceInstance.widgets` has been set (unless an error occurred when requesting the api)
deferred.resolve(widgetRestService.getAllWidgets());
});
return deferred.promise;
}])
Then, e.g. in a controller:
.controller("SomeController", ["$scope", "OtherService"
function ($scope, OtherService) {
OtherService.then(function (allWidgets) {
$scope.allWidgets = allWidgets;
});
}])
In my angular module I wrote a generic http handler for all my ajax requests.'
I was expecting that I could use the service across controllers, but my problem is the promise seems to be global.
Once ControllerOne uses the mapi_loader service, when I load AnotherController (by ng-click="go('/$route_to_load_another_controller')"), AnotherController is loaded a promise that has already returned from ControllerOne even though the URL they fetch are totally different.
So I guess my question is how do I write a service I could use across controllers? Do I really need to write a separate service for each controller where their only difference in code is the URL passed for $http.jsonp?
angular.module('myAppControllers',[])
.service('mapi_loader', ['$http', function($http) {
var promise;
var myService = {
fetch: function(url) {
if ( !promise ) {
promise = $http.jsonp(url)
.then(function (response) {
return response.data.nodes;
});
}
return promise;
}
};
return myService;
}])
.controller('ControllerOne', ['$scope', 'mapi_loader', function ($scope, mapi_loader) {
mapi_loader
.fetch("http://host.com/mapi_data_for_controller_one?callback=JSON_CALLBACK")
.then(function(data) {
$scope.useme = data;
});
}])
.controller('AnotherController', ['$scope', 'mapi_loader', function ($scope, mapi_loader) {
mapi_loader
.fetch("http://host.com/mapi_data_for_another_controller?callback=JSON_CALLBACK")
.then(function(data) {
$scope.useme = data;
});
}])
;
try something like this
angular.module('myAppControllers',[])
.service('mapi_loader', function($http) {
var alreadyLoading = {};
return {
fetch: function(url) {
if ( url in alreadyLoading ) {
return alreadyLoading[url];
}
return alreadyLoading[url] = $http.jsonp(url)
.then(function (response) {
delete alreadyLoading[url];
return response.data.nodes;
});
}
};
})
.controller('ControllerOne', function ($scope, mapi_loader) {
...
})
.controller('AnotherController', function ($scope, mapi_loader) {
...
});
I have coded the following service:
angular.module('App')
.factory('TestService', ['$http', '$q', '$resource', function (
$http, $q, $resource) {
var TestResource = $resource('/api/Tests', {}, {
saveData: { method: 'PUT' },
deleteData: { method: "DELETE", params: { TestId: 0 } }
});
var factory = {
query: function (selectedSubject) {
var deferred = $q.defer();
TestResource.query({ subjectId: selectedSubject },
function (resp) {
deferred.resolve(resp);
}
);
return deferred.promise;
//return Test.query({ subjectId: selectedSubject });
}
}
return factory;
}]);
In my controller I am calling it this way:
TestService.query($scope.selectedSubject)
.then(function (result) {
$scope.gridData = result;
}, function (result) {
alert("Error: No data returned");
});
Is there a way that I could cut out a few lines of code by not having $q in my service. Is there a way that I could return a promise from the $resource? I have tried the commented out code but that gives me an error saying there is no ".then" method.
$resource can't return a promise in the current stable version of Angular (1.0.8), but it looks like it'll come in version 1.2. It was added in v1.1.3 (v 1.1 is the unstable branch):
$resource: expose promise based api via $then and $resolved (dba6bc73)