Multiple post requests in the same method in Angular - javascript

$scope.observer_vel_data = function(){
$scope.showOverlay('loadRefPubVel');
$http({
//First http post request
method:'POST',
url:'/api/observer_vel_data',
data:$scope.payload_array,
}).then(function successCallback(response){
console.log('API Endpoint: vel data success!');
//Second post request is made in the method call below
$scope.sentiment_var = $scope.observer_send_sentiment();
$scope.vel_var = response.data.velocity1;
}, function errorCallback(response){
// console.log(response);
$scope.addAlert({
type: 'danger',
msg: 'API call failed'
});
}).finally(function(){
console.log("hello");
console.log($scope.sentiment_var);
//graph is rendered
$scope.update_velocity($scope.vel_var,$scope.sentiment_var);
$scope.hideOverlay('loadRefPubVel');
});
};
So I am trying to render a graph which uses data from two different and independent post requests. However, the graph command is called before the data from the second post request arrives. How can I fix this ? The commands which make the post requests and render the graph are mentioned as comments in the code posted.
$scope.observer_send_sentiment = function (){
// $scope.showOverlay('loadRefSentiment');
var data = {
"angularGroups":$scope.groups
};
// console.log(data);
$http({
method:'POST',
url:'http://localhost:9612/sentiment_velocity',
data:data
}).then(function successCallback(response){
var data = response.data;
var json_obj = JSON.parse(data.replace(/\'/g,'"'));
var sentiments = json_obj["sentiments"];
// console.log(sentiments);
$scope.update_sentiment(sentiments);
console.log(sentiments);
return sentiments;
}, function errorCallback(response){
var errmsg = response.statusText;
console.log(response);
$scope.addAlert({
type: 'danger',
msg: 'API call failed (sentiment basic)' + errmsg,
});
}).finally(function(){
// $scope.hideOverlay('loadRefSentiment');
});
};

If I understand correctly, you want the code in finally(...) execute only after the second request ends.
To enforce that, you need to chain the HTTP request promises, meaning you need to return the promise of the second HTTP request from the success handler of the first request. Your code should look like more or less like this:
$scope.observer_vel_data = function(){
$scope.showOverlay('loadRefPubVel');
$http({
method:'POST',
url:'/api/observer_vel_data',
data:$scope.payload_array,
}).then(function successCallback(response){
console.log('API Endpoint: vel data success!');
$scope.vel_var = response.data.velocity1;
return $scope.observer_send_sentiment();
}).catch(function errorCallback(response) {
//This catch will handle errors from both HTTP requests
$scope.addAlert({
type: 'danger',
msg: 'API call failed'
});
})
.finally(function(){
console.log("hello");
console.log($scope.sentiment_var);
//graph is rendered
$scope.update_velocity($scope.vel_var,$scope.sentiment_var);
$scope.hideOverlay('loadRefPubVel');
});
};
$scope.observer_send_sentiment = function() {
return $http({...}).then(function(response) {
//process the response
...
$scope.sentiment_var = parsedResponseData;
});
};
Note that the finally callback will always execute, regardless of whether an error occured or not. If you want some of it to execute only if an error was not encountered, add another .then(function() {...}) instead.
EDIT: Now that we can that see what observer_send_sentiment does, it might make sense for you to stick to the .then(function successCallback() {...}, function errorCallback() {...}) syntax, and keep separate error callbacks for each of the requests. Just keep in mind that if you ever add another then block and you want errors along the promise chain to prevent executing further .then(function() {...}) blocks, you should add return $q.reject(response) at the end of both errorCallbacks. Not using q.reject from within error callbacks with the .then(function successCallback() {...}, function errorCallback() {...}) syntax renders the promise resolved, not rejected.

Related

Cannot .catch() an error when using Jquery.ajax().then()

I am hitting a number of API's from JQuery, and caching the result of each so that the data can be re-used multiple times in the page to render some dashboard widgets in different formats.
The problem is that if an API returns a 500 status code with error, I don't want to try and draw the widget, but capture the error in a friendly way.
However, I cannot figure out how .catch works with the JQuery.ajax() function. After reading here, here, here, here and a dozen others, I've got so far but always get the same console error:
TypeError: LoadDataFromApi(...).then(...).catch is not a function
I've tried to comment the code to explain what I'm trying to do at each stage. Please somebody explain why the whole .catch thing isn't working for me.
// Cache object to save API data for re-use
var requestCache = {};
// Get API data and save to cache
function LoadDataFromApi(apiUrl) {
if (!requestCache[apiUrl]) {
var result = $.ajax({
type: 'GET',
url: apiUrl,
dataType: "json",
statusCode: {
500: function (xhr) {
var err = JSON.parse(xhr.responseText);
console.log('Message:' + err.Message);
// throw err.Message; // removed because this was always an "uncaught exception", even if used within try/catch
},
200: function (xhr) {
// Do nothing here - put result into cache regardless of status code
}
}
});
requestCache[apiUrl] = result; // save the JSON data into cache
}
return requestCache[apiUrl];
}
// Called by page on load
function LoadJsonData() {
LoadDataFromApi('/api/GetFoo?Row=10')
.then(function (data) {
RenderChart(data, 'Removed for legibility');
})
.catch(function (error) {
console.log('Promise catch: ' + error);
});
LoadDataFromApi('/api/GetFoo?Row=10') // this returns cached data because API has already been hit
.then(function (data) {
RenderChart(data, 'Removed for legibility');
})
.catch(function (error) {
console.log('Promise catch: ' + error);
});
LoadDataFromApi('/api/GetBar')
.then(function (data) {
RenderChart(data, 'Removed for legibility');
})
.catch(function (error) {
console.log('Promise catch: ' + error);
});
}
Use .fail() as described in your first link here
Depending on your jQ version
"Deprecation Notice: The jqXHR.success(), jqXHR.error(), and
jqXHR.complete() callbacks are removed as of jQuery 3.0. You can use
jqXHR.done(), jqXHR.fail(), and jqXHR.always() instead."
EDIT:
You error callback should accept 3 arguments, so make it so
function(jqXHR,textStatus,errorThrown ){}
JQuery does not return typical promise, it's$.Deferred in that case:
http://api.jquery.com/jquery.ajax/
http://api.jquery.com/category/deferred-object/
More on that here, with answers:
Deferred versus promise

How to get error from http service

I am trying to get http error if service failed to load a url. I have created a angular factory which is like this:
loadUsers: function () {
return $http.get(urlService.url("/users"));
},
in controller i try to using this factory method to load ruserlist:
urlservice.loadUsers()
.then(function(response) {
$log.info("user loaded");
})
.finally(data.bind(undefined, result));
at this point i want to handle http error but not getting idea where i have to use error function as this is returning a promise. Can someone give me hint.
Just add a .catch to your promise:
urlservice.loadUsers()
.then(function(response) {
$log.info("user loaded");
})
.catch(function(err) {
console.log(err);
})
.finally(data.bind(undefined, result));
add a second callback to the .thenmethod, that will be triggered in case of error.
from the angular doc:
https://docs.angularjs.org/api/ng/service/$http
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Just add another function inside promise like this
urlservice.loadUsers()
.then(function(response) {
$log.info("user loaded");
},function(response) {
$log.info("error");
})
.finally(data.bind(undefined, result));
urlservice.loadUsers().then(successCallback, errorCallback)
.finally(data.bind(undefined, result));
var successCallback = function(response) {
// handle data recieved
$log.info("user loaded");
};
// create generic method for handling service errors
var errorCallback = function(error) {
// handle error here
$log.info("error occurred");
};

Angular HTTP Interceptor not hitting error functions

So I have pulled the interceptor straight from the angular HTTP documentation and yet this still doesn't work. The "request" and "response" functions get called ,but never the "requestError" or the "responseError".
myApp.config(['$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push(function ($q) {
return {
'request': function (config) {
return config; //gets called
},
'requestError': function (rejection) {
return $q.reject(rejection); //Never gets called
},
'response': function (response) {
return response; //gets called
},
'responseError': function (rejection) {
return $q.reject(rejection); //Never gets called
}
};
});
}]);
On the server I am returning a 400, but really any error would do. And here is the service
User.publicProfileGetProfile = function (value, type) {
return $http({
url: '/public/profile/' + type + '/' + value,
method: 'GET'
}).then(function (response) {
return response;
}, function(error){
return error;
});
};
No error functions are being called and every response goes through the response function. The standard angular error is displayed with the Bad Request (400) as usual. When the 400 error is returned, it is simply 'undefined' through the 'response' function in the interceptor.
Let me know if I've forgotten to include any important information.
By using return, the error handler is converting the rejection to a success. Instead use throw to chain the rejection.
User.publicProfileGetProfile = function (value, type) {
return $http({
url: '/public/profile/' + type + '/' + value,
method: 'GET'
}).then(function onSuccess(response) {
return response;
}, function onReject(error){
//return converts rejection to success
//return error;
//use throw to chain rejection
throw error;
});
};
When I saw that the JSFiddle (from #georgeawg) was working properly, I made sure mine looked exactly the same. When it didn't work, I looked around to see if I had any other interceptors that might cause problems. I had another interceptor that was being hit first and returning any errors as responses, then they would go through this one and it would process it as a successful response. I removed it and everything seems to be working correct now!

How to get response from service on controller

I'm trying to separate the $http.post() call into a ".factory()", But would like to fetch the response which is coming async on the controller. Is there a way of doing that?
Controller:
Login.post($scope.user);
Factory:
.factory( 'Login' , function($http,SERVERURL){
var serverUrl = SERVERURL;
return {
'post' : function(user){
$http.post(serverUrl+'/login', user).
then(function(response) {
console.log(response);
}, function(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}
};
})
There is a .then() but I want that on the controller, so I can behave accordingly. Thank you!
Basically you need to return the $http.post promise, and from success function you could return a data that will return to the consumer of this method. So that you could easily call the factory method from controller & inside .then function of that call you could have success and error function.
Code
.factory('Login', function($http, SERVERURL) {
var serverUrl = SERVERURL;
return {
'post': function(user) {
return $http.post(serverUrl + '/login', user).
then(function(response) {
console.log(response);
return response.data; //return data from here
}, function(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}
};
})
Controller
Login.post().then(function(data){ //success function
console.log(data)
}, function(error){ //error function
console.log(error);
})
You could add a callback param.
.factory( 'Login' , function($http,SERVERURL){
var serverUrl = SERVERURL;
return {
'post' : function(user, callback){
$http.post(serverUrl+'/login', user).
then(function(response) {
console.log(response);
callback(null, response);
}, function(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
callback(response);
});
}
};
})
And your controller will become:
Login.post($scope.user, function(err, response) {
if(err) {} //do something if there is an error
// or deal with the response
});
To return any response to controller just do:
return {
'post' : function(user){
return $http.post(serverUrl+'/login', user);
}
};
In your controller you will already call.then()
Angular's $http methods return a Promise.
The $http API is based on the deferred/promise APIs exposed by the $q service.
Factory
Your method post is not yet returning anything but can quite simply return the Promise which is created by calling $http.post:
.factory('Login' , function($http, SERVERURL){
var serverUrl = SERVERURL;
return {
'post' : function (user) {
return $http.post(serverUrl + '/login', user)
// ^^^^^^
.then(function (response) {
console.log(response);
return response.data;
}, function (response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
}
};
});
Controller
Then consume the result of the returned Promise by calling then on it:
Login.post($scope.user).then(function (res) {
// do something with `res`...
});

angularjs and $http request

Hello I'm new to AngularJs and trying to get json Data from my server. When the service gets executed, I see a clear response in Fiddler. But the success or the error function does not get executed, and so the service returns an empty array.
var app = angular.module('imageApp', []);
app.service('imageService', function ($http) {
var imageModels = [];
this.Images = function (url) {
$http({ method: 'GET', url: url }).success(function (data) {
imageModels = data;
}).error(function (data) {
imageModels = data || "Request failed";
});
return imageModels;
};
};
});
app.controller('ImageController', function (imageService, $scope) {
$scope.fetch = function (url) {
$scope.url = url;
$scope.ImageModels = imageService.Images($scope.url);
};
});
$http returns results asynchronously. So, return imageModels will execute before the success() or error() callbacks have had a chance to run. You need to wait for the promise that $http creates to resolve -- use then() in your controller.
Rather than repeat it here, see the solution from #Pete BD: https://stackoverflow.com/a/12513509/215945
Update your service like this.
app.service('imageService', function ($http, $q) {
this.Images = function (url) {
return $http({ method: 'GET', url: url }).success(function (data) {
$q.resolve(data);
}).error(function (data) {
$q.reject(data || "Request failed");
});
};
});
Then your controller, you can now wait for a promise to be returned from the service.
imageService.Images($scope.url)
.then(function(response){
// success
}).catch(function(error){
// error
})
So what happened? On your service, notice that we added $q to create a promise so we can reslove and reject the response from $http and make it "thenable" on the controller.
Writing a service to handle $http request is always a hassle for me, so I created this angular module to handle things for me. If you want you can check it out.

Categories

Resources