I am trying to get response message from jsonp error callback in angularjs, but response data is undefined. I return the response with 409 http code. If to open jsonp url directly in browser it shows "angular.callbacks._0({"message":"Reset link is incorrect"})", but I can't get this message in error callback. What am I doing wrong?
// Extend angular app for api requests
app.factory('User', function($http) {
var User = function(data) {
angular.extend(this, data);
};
// Send link for password reset to entered email
User.reset_password = function() {
return $http.jsonp(jsonp_url + 'user/reset_pass?_method=post&user_key=' + user_key + '&callback=JSON_CALLBACK');
};
return User;
});
app.controller('ResetPasswordController', function ResetPasswordController($scope, User){
$scope.submit = function() {
var response = User.reset_password();
response.then(function(data){
//Success callback
}, function(data){
// Error callback
console.log(data) // Output: {config : {...}, data: undefined}
});
}
});
As said Brandon Tilley it is not possible to get data from jsonp response with http error code. If you want anyways to get error message you need to send something like this {result: false, msg: 'Error occured...'} with "good" http code, for example 200.
Related
In my controller i want send a request using get method if $http, in that get method i want to send the sessionID in headers. Below am giving the code snippet please check.
this.surveyList = function () {
//return session;
return $http.get('http://op.1pt.mobi/V3.0/api/Survey/Surveys', {headers: { 'sessionID': $scope.sessionid}})
.then(function(response){
return response.data;
}, function(error){
return error;
});
}
but this is not working when i send this vale in backend they getting null.
So how to resolve this.
we have a issue where the api is getting called twice from angular , however it works only once when called with the POSTMAN. And here with the custom header passed to the api, the action is called twice. What could be the reason for it?
Try in this way,
$http({
method: 'GET',
url: 'http://op.1pt.mobi/V3.0/api/Survey/Surveys',
headers: {
'sessionId': $scope.sessionid
}
}).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.
});
UPDATE: I tried another API: http://www.omdbapi.com/?t=Sherlock
And the GET works. However, I'm still unsure why my node.js server API does not work with this method.
I am currently working on the backend of an app of which I created an API similar to the tutorial: https://codeforgeek.com/2015/03/restful-api-node-and-express-4/.
However, I cannot seem to get my ionic angular app to retrieve my JSON result. When I put my get command on Postman, I get :
[{"floor":3}]
My controller is:
$http({url:"http://localhost:3000/api/fl",method:'GET'})
.then(function(response) {
$scope.status = response.status;
$scope.data = response.data;
$log.log("success");
$log.log("res:"+ response);
}, function(response) {
$scope.data = response.data || "Request failed";
$scope.status = response.status;
$log.log("failed");
$log.log("res:"+ response);
});
$log.log("status: "+$scope.status);
$log.log("data: "+$scope.data);
(my /fr references the JSON which has a GET method on my node server)
And always gives the result of "failed", "status: undefined" as well as "data: undefined". When I recurse this method, it gives me a "status:0".
I have also tried using $resource with no success.
Any guidance would be appreciated. My API does not have any auth and I don't think it has anything to do with CORS(unless you guys think it does).
EDIT:
this is the get method on my server.js:
//GET Floor
router.get("/fl",function(req,res){
var query = "SELECT floor FROM stor1 WHERE id=0";
connection.query(query,function(err,rows){
if(err) {
res.json({"Error" : true, "Message" : "Error executing MySQL query"});
} else {
res.json(rows);
}
});
});
EDIT2:
Well, i added more logs to display results and now i get an [object Object] from response. The object is:
{"data":null,"status":0,"config":{"method":"GET","transformRequest":[null],"transformResponse":[null],"url":"http://localhost:3000/api/fl","headers":{"Accept":"application/json, text/plain,*/*"}},"statusText":""}
Your postman seems to get the response for the GET request which means your server side code is fine with routing. But your Angular App is unable to get any response with out throwing any error in the server side. Which seems to be the case of CORS
var cors = require('cors');
app.use(cors());
Note: Use this middleware before your first route.
There is one more way to make Access-Control-Allow-Origin
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
next();
});
Try adding names for the success and error callback functions, like so:
$http({url:"http://localhost:3000/api/fl",method:'GET'})
.then(function successCallBack(response) { // Add 'successCallBack' function name
$scope.status = response.status;
$scope.data = response.data;
$log.log("success");
$log.log("res:"+ response);
}, function errorCallBack(response) { // Add 'errorCallBack' function name
$scope.data = response.data || "Request failed";
$scope.status = response.status;
$log.log("failed");
$log.log("res:"+ response);
});
$log.log("status: "+$scope.status);
$log.log("data: "+$scope.data);
I have a controller which uses the following line to post data to server through a factory called SendDataFactory:
SendDataFactory.sendToWebService(dataToSend)
And my factory SendDataFactory looks like this:
angular
.module('az-app')
.factory('SendDataFactory', function ($http, $q) {
var SendData = {};
/**
* Sends data to server and
*/
SendData.sendToWebService = function (dataToSend) {
var url = "example.com/url-to-post";
var deferred = $q.defer();
$http.post(url, dataToSend)
//SUCCESS: this callback will be called asynchronously when the response is available
.then(function (response) {
console.log("Successful: response from submitting data to server was: " + response);
deferred.resolve({
data: data
});
},
//ERROR: called asynchronously if an error occurs or server returns response with an error status.
function (response) {
console.log("Error: response from submitting data to server was: " + response);
deferred.resolve({
data: data
});
}
);
return deferred.promise;
}
return SendData;
});
I have seen some examples in here and the internet with
$http.post().success...
but I want to use
$http.post().then...
since angular documentation says:
The $http legacy promise methods success and error have been deprecated. Use the standard then method instead. If $httpProvider.useLegacyPromiseExtensions is set to false then these methods will throw $http/legacy error.
What I need:
Now in my controller I need to check if the $http.post().then... was successful or not and then do something based on success or fail. How can I achieve this?
I think this is what you meant:
$http.post(url, dataToSend)
//SUCCESS: this callback will be called asynchronously when the response is available
.then(function (response) {
console.log("Successful: response from submitting data to server was: " + response);
deferred.resolve({
data: response //RETURNING RESPONSE SINCE `DATA` IS NOT DEFINED
});
},
//ERROR: called asynchronously if an error occurs or server returns response with an error status.
function (response) {
console.log("Error: response from submitting data to server was: " + response);
//USING THE PROMISE REJECT FUNC TO CATCH ERRORS
deferred.reject({
data: response //RETURNING RESPONSE SINCE `DATA` IS NOT DEFINED
});
}
);
return deferred.promise;
}
In your controller you now can use:
SendDataFactory.sendToWebService(dataToSend)
.then(function(data) { /* do what you want */ })
.catch(function(err) { /* do what you want with the `err` */ });
Reject the promise instead of resolving it when it is rejected by $http.
/**
* Sends data to server and
*/
SendData.sendToWebService = function (dataToSend) {
var url = "example.com/url-to-post";
var deferred = $q.defer();
$http.post(url, dataToSend)
//SUCCESS: this callback will be called asynchronously when the response is available
.then(function (response) {
console.log("Successful: response from submitting data to server was: " + response);
deferred.resolve(response.data); // Resolving using response.data, as data was not defined.
},
//ERROR: called asynchronously if an error occurs or server returns response with an error status.
function (response) {
console.log("Error: response from submitting data to server was: " + response);
deferred.reject(response.data); // Rejecting using response.data, as data was not defined.
}
);
return deferred.promise;
}
You can then call it from your controller the same way as you handle the callback in the service using then.
Since $http returns a promise, it can be simplified further though using promise chaining. This way there is no need to use an extra deferred object.
/**
* Sends data to server and
*/
SendData.sendToWebService = function (dataToSend) {
var url = "example.com/url-to-post";
return $http.post(url, dataToSend)
//SUCCESS: this callback will be called asynchronously when the response is available
.then(function (response) {
console.log("Successful: response from submitting data to server was: " + response);
return response.data; // Resolving using response.data, as data was not defined.
},
//ERROR: called asynchronously if an error occurs or server returns response with an error status.
function (response) {
console.log("Error: response from submitting data to server was: " + response);
return $q.reject(response.data); // Rejecting using response.data, as data was not defined.
}
);
}
i have written a service with take parameter on the basis of which it response me with the response of http request.
this.getPaymentDueDetails=function(date){
this.getfromRemote('paymentdue/'+btoa(date))
.success(function(response){
return response;
})
.error(function(response){
return false;
})
}
getfromRemote is my another service which make http request
now i am trying to get the response of this service call inside my controller function
$scope.callDueReports=function(blockNum){
var data;
data=myAngService.getPaymentDueDetails('2015-04-20');
console.log(data);
}
its quite obvious that i wont get any thing in data as the page loads initially but i want the result of getPaymentDueDetails int it.
Please modify your service to return the promise like below.
this.getPaymentDueDetails = function(date) {
return this.getfromRemote('paymentdue/' + btoa(date));
};
And in controller check if the promise is resolved.
$scope.callDueReports = function(blockNum) {
var data;
myAngService.getPaymentDueDetails('2015-04-20').then(function(dataFromService) {
data = dataFromService;
console.log(data);
})
.catch(function(response) {
console.error('error');
});
};
So I have a bunch of controllers that do $http requests
but in every $http request i have a .error(function(data...){//always the same})
How could I build an.. "abstract class" for $http?
This here would be the always repeating code
.error(function(){
$scope.flashes = {
server: {
type: "danger",
message: "There was a server error processing your request. Please try again later."
}
};
})
I add the same concern few weeks ago and i came up with this solution :
I first created a custom service intercepting every http requests made :
.factory('HttpInterceptor', ['$q', '$rootScope', function($q, $rootScope) {
return {
// On request success
request : function(config) {
// Return the config or wrap it in a promise if blank.
return config || $q.when(config);
},
// On request failure
requestError : function(rejection) {
//console.log(rejection); // Contains the data about the error on the request.
// Return the promise rejection.
return $q.reject(rejection);
},
// On response success
response : function(response) {
//console.log(response); // Contains the data from the response.
// Return the response or promise.
return response || $q.when(response);
},
// On response failure
responseError : function(rejection) {
//console.log(rejection); // Contains the data about the error.
//Check whether the intercept param is set in the config array. If the intercept param is missing or set to true, we display a modal containing the error
if (rejection.config && typeof rejection.config.intercept === 'undefined' || rejection.config.intercept)
{
//emitting an event to draw a modal using angular bootstrap
$rootScope.$emit('errorModal', rejection.data);
}
// Return the promise rejection.
return $q.reject(rejection);
}
};
}]);
I also defined a custom config property 'intercept' that i can add to the $http config object. It is useful when I don't want to apply this behavior on a particular request.
E.g :
var registerResource = $resource('/registration/candidate/register', {}, {query:
{method:'POST', isArray: false, intercept: false }
});
In order the have a flexible solution, it is also important to not forget to do :
return $q.reject(rejection);
So you can still use the error callback on your promise in your controller if you want to combine both ways (interception + manual handling)
Finally, I added this service to my application :
app.config(['$httpProvider', function($httpProvider) {
// Add the interceptor to the $httpProvider to intercept http calls
$httpProvider.interceptors.push('HttpInterceptor');
}]);
I simplified the service but you can also use it for many things. Personally, I also use it to :
Make sure to not fire duplicate http requests (if the user click a lot on a submit button).
Draw an alert at the beginning of an http call and close it at the end to inform the user that is treatment is processing (export of data for instance).
PS: The official documentation mention this interceptor
You could do something like this:
app.service('myHttp', function($http){
return function($scope, httpParameters){
var httpPromise = $http(httpParameters);
httpPromise.error(function(){
$scope.flashes = {
server: {
type: "danger",
message: "There was a server error"
}
}
});
};
});
app.controller('MainCtrl', function($scope, myHttp) {
myHttp($scope, {method: 'GET', url: 'www.google.com'});
});