angularJS: order of promise - angularjs

I have two promises:
getToken() //:get a CSFR cookie from the server
and
getUseraData() //:get user data, but it need the cookie get from getToknen() otherwise server respond with an error.
So, I know that I can do this in my controller:
getToken().then(function (result) {
getUserData(result);
});
But I know that it is not so good to run a promise inside a promise.
So: how can I exec the getUserData() promise only after that getToken is terminard and a value is returned?

There is nothing wrong with chaining promises, which is what you are doing, as long as you don't forget to return a promise, so do it like this:
var getUserDataPromise = getToken().then(function (result) {
return getUserData(result);
});
Or like this:
getToken().then(function (result) {
return getUserData(result);
}).then(function(getUserDataPromiseResult){
//here you will have the getUserData promise resolved
});
Notice that for this to work you need to return a promise. I insist: this is not a bad practice, this is a very common practice

you can use deferred function.. you need to inject $q..
create a service then add your getToken http request code.. like this
myapp.factory('myService',$q,$http){
var deferred = $q.defer();
var newVal = { 'Value': val };
var getToken = functino(){ $http({
method: 'PATCH',
url: baseService.getBaseService + 'ModuleAndParameters(' + ModAndParamsId + ')',
data: newVal
}).success(function (data, status, headers, config) {
deferred.resolve(data)
}).error(function (data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
};
return getToken;
}
then in your controller,, inject the name of your service.. and just simply do it like this..
myService.getToken().then(function(result){
getUserData(result);
})
i hope it helped..xD

Related

using the data from the post request

I pass two dates to the post method thro controller.The service responses back with some data based on the given input. Im using $scope.onGetData to get the data from post method, inorder to display the final result but it is not going inside the $scope.onGetData. So the question is how to fetch the response data from the service and use it inside a controller, so that I can make use of it in my view.
Controller:
$scope.computationList;
$scope.onViewLoaded = function () {
computationManagementService.getComputation($scope.onGetData);
}
$scope.onGetData = function (data,response,error) {
$scope.computationList = data;
}
$scope.calculateInput=function(start,end,htmlValidation)
{
var date={'startDate':start , 'endDate':end};
if(htmlValidation){
computationManagementService.getComputation(date,function(err,response){
console.log("pass thro controller");
});
}else{
console.log("Validation Error");
}
}
});
Service:
myApp.factory('computationManagementService', function($http, settings){
var ComputationServiceFactoryObj = {};
var _getComputation= function(date,callback){
$http({
method:'POST',
url: 'localhost:/8091/date/computation',
data: date
}).success(function(data,response,config){
callback(response);
console.log(data); // data
}).error(function (data, status, error, headers, config){
if(callback) {
callback(error);
console.log(error);
}
});
}
ComputationServiceFactoryObj.getComputation= _getComputation;
return ComputationServiceFactoryObj;
});
If you are trying to use the post method's data to the view then you can try this method And it worked for me but not sure if it is correct way of using the service.
Service:
myApp.factory('computationManagementService',
function($http, $rootScope, settings){
var ComputationServiceFactoryObj = {};
var _getComputation=function(callback){
var computationData=$rootScope.finalResult;
if(callback != null){
callback(computationData);
}
}
var _postComputation= function(date,callback){
$http({
method:'POST',
url: 'localhost:/8091/date/computation',
data: date
}).success(function(data){
callback(data);
$rootScope.finalResult=data;
console.log(data); // data
}).error(function (data, status, error, headers, config){
if(callback) {
callback(error);
console.log(error);
}
});
}
ComputationServiceFactoryObj.getComputation= _getComputation;
ComputationServiceFactoryObj.postComputation= _postComputation;
return ComputationServiceFactoryObj;
});
Some good practices:
using ngResource is always preferable to the raw $http service, except for rare cases when you need some complex configuration that ngResource can't handle (I can't think of such, though). Why? It forces you yo use promises.
return promises from your service methods instead of passing callbacks. Using callbacks will force you to call $digest on your scope so that bingings are re-evaluated, which goes against the way angular works in general and may have negative performance impact as well.
In your case I'd modify the _getComputation method to simply return a promise:
var _getComputation = function(date) {
return $http({
method:'POST',
url: 'localhost:/8091/date/computation',
data: date
});
};
In your controller:
computationManagementService.getComputation(date)
.then(function(response) {
console.log(response);
$scope.someValue = response.someValue;
}, function(error) {
console.error(error);
});
I'd rather avoid injecting $scope in controllers, and use the ngController='MyController' as 'MyCtrl' syntax instead and assign values that should be accessible by views to the controller instance.
It is better not to use .success and .error methods in your service as they are not chainable, Use .then format instead. .success/error methods are deprecated in the latest Angular version 1.6.
Here is the Deprecation notice from Angular documentaion.
In your service :
var _getComputation= function(date,callback){
return $http({
method:'POST',
url: 'localhost:/8091/date/computation',
data: date
}).success(function(data,response,config){
callback(undefined, response);
console.log(data); // data
}).error(function (data, status, error, headers, config){
if(callback) {
callback(error);
console.log(error);
}
});
}
In your Controller :
computationManagementService.getComputation(date,function(err,response){
console.log("pass thro controller");
console.log(response);
}

synchronous http call in angularJS

I have the following scenario, I need data from a particular url. I have written a function which takes parameter 'url'. Inside the function I have the $http.get method which makes a call to the url. The data is to be returned to the calling function
var getData = function (url) {
var data = "";
$http.get(url)
.success( function(response, status, headers, config) {
data = response;
})
.error(function(errResp) {
console.log("error fetching url");
});
return data;
}
The problem is as follows, $http.get is asynchronous, before the response is fetched, the function returns. Therefore the calling function gets the data as empty string. How do I force the function not to return until the data has been fetched from the url?
Take a look at promises to overcome such issues, because they are used all over the place, in angular world.
You need to use $q
var getData = function (url) {
var data = "";
var deferred = $q.defer();
$http.get(url)
.success( function(response, status, headers, config) {
deferred.resolve(response);
})
.error(function(errResp) {
deferred.reject({ message: "Really bad" });
});
return deferred.promise;
}
Here's a nice article on promises and $q
UPDATE:
FYI, $http service itself returns a promise, so $q is not necessarily required in this scenario(and hence an anti-pattern).
But do not let this be the reason to skip reading about $q and promises.
So the above code is equivalent to following:
var getData = function (url) {
var data = "";
return $http.get(url);
}
You can use $q.all() method also to solve this problem
var requestPromise = [];
var getData = function (url) {
var data = "";
var httpPromise = $http.get(url)
.success( function(response, status, headers, config) {
data = response;
})
.error(function(errResp) {
console.log("error fetching url");
});
requestPromise.push(httpPromise);
}
in the calling function
$q.all(requestPromise).then(function(data) {
//this is entered only after http.get is successful
});
make sure to inject $q as a dependency. Hope it helps
You function seems redundant. Just use $http.get(url), since you aren't really doing anything else before you use it anyway.
var url = 'foo/bar';
$http
.get(url)
.success( function(response, status, headers, config) {
$scope.data = response;
})
.error(function(errResp) {
console.log("error fetching url");
});
Or if you need to access the promise later just assign it to variable;
var promise = $http.get(url);
// some other code..
promise.then(function(data){
//.. do something with data
});
A typical way to do what you want is like so:
var getData = function(url, callback) {
$http.get(url).success(function(response) {
callback && callback(response);
});
};
Used like:
getData('/endpoint', function(data) {
console.log(data);
});

Catching Angular promise success response twice

It seems that the console output will always be:
This is the first response
This is the second response
because the success function of the inner method will be invoked first. Is this a correct assumption? Is the order guaranteed?
app.controller("ctrl", function($scope,$http) {
var getUrl = function () {
var config = {
method: 'GET',
url: 'some.txt'
};
return $http(config)
.success(function (response, status, headers, config) {
console.log('This is the first response');
})
.error(function (data, status, headers, config) {
});
};
var init = function () {
var promise = getUrl();
promise.then(
function() {
console.log('This is the second response');
});
};
init();
});
Yes, because $http return a promise itself and what you do above is promise chaining.
Although it might be better to use $http.then(success,error).then(success,error);

Where in angular should I put this code?

I have an http-method that gets some data from a google spreadsheet. I want to add this to the $scope so I can output it in the DOM. Later I might make a timed loop of this so that the $scope get's updated every 5 seconds or so.
I currently run the code in app.run:
angular.module('spreadsheet2angular', []).
run(function($http){
$http({method: 'GET', url: 'http://cors.io/spreadsheets.google.com/feeds/cells/0Aq_23rNPzvODdFlBOFRYWlQwUFBtcXlGamhQeU9Canc/od6/public/values?alt=json'}).
success(function(data, status, headers, config) {
var entries = data.feed.entry;
var phraces = [];
entries.forEach(function(entry){
var cell = entry.gs$cell;
if(!phraces[cell.row]){
phraces[cell.row] = {};
}
if(cell.col == 1)
{
phraces[cell.row].name = cell.$t;
}
else if(cell.col == 2)
{
phraces[cell.row].value = cell.$t;
}
});
phraces.forEach(function(phrace){
console.log(phrace);
});
}).
error(function(data, status, headers, config) {
console.log('error');
});
});
I'm new to angular, is this the best place to run it? I would like to run it as something that is easily reusable in different projects.
I think from what you've explained, a service would be perfect. Build it out then inject it in your controller. You can then call/use that service object whenever you would like.
I would use service/factory that returns promise. So we call async service method, get back promise and parse response into controller.
If you think to use the same call in the future, you can write generic method.
By the same way, if you are going to parse response by the same way in the future, the part of logic I would put into the service as well and wrap with $q . So the response still will be promise.
And this is an example I use that might help you to understand what I'm meaning:
app.service('apiService', ['$http', '$q', '$rootScope',
function($http, $q, $rootScope) {
var request = function(method, data) {
var deferred = $q.defer();
var configHttp = {
method: 'POST',
url: config.api + '/' + method
};
if (data !== undefined) {
configHttp.data = data;
}
$http(configHttp).success(function(data, status, headers) {
if (data.error === undefined) {
deferred.resolve(data);
} else {
deferred.reject(data);
}
}).error(function(data, status, headers) {
deferred.reject(data);
});
return deferred.promise;
}
return {
getItem: function() {
return request('get_item');
},
getItemByParams: function(id) {
return request('get_item_by_params', {id: id});
}
};
}
]);

AngularJS - Controller gets the data returned from Service (MVC Web API call) as undefined

I am new to AngularJS & working on a sample. In my sample app I have an MVC Web api (which returns some data from db) & it will be called from the Angular Services and returns the data to the Controller. The issue is I am getting the data in my Services success method properly but in my controller it always shows undefined & nothing is displayed in the view. Please see the code below:
My Controller code:
app.controller('CustomerController', function ($scope, customerService) {
//Perform the initialization
init();
function init() {
$scope.customers= customerService.getCustomers();
}
});
My Services code:
app.service('customerService', function ($http){
this.getCustomers = function () {
$http({
method: 'GET',
url: 'api/customer'
}).
success(function (data, status, headers, config) {
return data;
}).
error(function (data, status) {
console.log("Request Failed");
});
}
});
Please help me to fix this issue.
That's because your service defines the function getCustomers but the method itself doesn't actually return anything, it just makes an http call.
You need to provide a callback function in the form of something like
$http.get('/api/customer').success(successCallback);
and then have the callback return or set the data to your controller. To do it that way the callback would probably have to come from the controller itself, though.
or better yet, you could use a promise to handle the return when it comes back.
The promise could look something like
app.service('customerService', function ($http, $q){
this.getCustomers = function () {
var deferred = $q.defer();
$http({
method: 'GET',
url: 'api/customer'
}).
success(function (data, status, headers, config) {
deferred.resolve(data)
}).
error(function (data, status) {
deferred.reject(data);
});
return deferred;
}
});
Your problem is in your service implementation. You cannot simply return data since that is in the asynchronous success callback.
Instead you might return a promise and then handle that in your controller:
app.service('customerService', function ($http, $q){
this.getCustomers = function () {
var deferred = $q.defer();
$http({
method: 'GET',
url: 'api/customer'
})
.success(function (data, status, headers, config) {
// any required additional processing here
q.resolve(data);
})
.error(function (data, status) {
q.reject(data);
});
return deferred.promise;
}
});
Of course if you don't require the additional processing, you can also just return the result of the $http call (which is also a promise).
Then in your controller:
app.controller('CustomerController', function ($scope, customerService) {
//Perform the initialization
init();
function init() {
customerService.getCustomers()
.then(function(data) {
$scope.customers= data;
}, function(error) {
// error handling here
});
}
});
VERY late answer, but, Angular's $http methods return promises, so there's no need for wrapping everything into promise form with $q. So, you can just:
app.service('CustomerService', function ($http) {
this.getCustomers = function () {
return $http.get('/api/customer');
};
});
and then call the .success() or .error() shortcut methods in your client controller.
If you want to take it a step further and have a fully-fledged RESTful CustomerService without having to write this boilerplate, I'd recommend the restangular library, which makes all sorts of methods available to you - assuming of course your backend responds to HTTP verbs in the "standard fashion".
Then you could just do this:
app.service('CustomerService', function (Restangular) {
return Restangular.service('api/customer');
});
and call the methods Restangular makes available to you.
I use this for communication between Angular Web Data Service and Web Api Controller.
.factory('lookUpLedgerListByGLCode', function ($resource) {
return $resource(webApiBaseUrl + 'getILedgerListByGLCode', {}, {
query: { method: 'GET', isArray: true }
});
})
OR
.factory('bankList', function ($resource) {
return $resource(webApiBaseUrl + 'getBanklist_p', {}, {
post: {
method: 'POST', isArray: false,
headers: { 'Content-Type': 'application/json' }
}
});
})

Resources