angular jsonp factory doesn't work - angularjs

I have this factory in angular, and its returning me a 0 error code always, even tho i can see it fetches from the json origin, can someone help me?
app.factory('docFactory', function($http) {
var docFactory = {
async: function(page) {
var url = 'http://example.com/ProviderRequest?&queryString=searchv2&callback=JSON_CALLBACK';
var promise = $http.jsonp(url).error(function (response, status) {
alert(status);
}).success(function (response, status) {
alert(status);
}).then(function (response, status) {
return response.data;
});
return promise;
}};
return docFactory;
});

I ran into this myself. If your JSONP is a function call or something falsy (null, false, undefined) you will encounter this behavior. Take a look at this code from AngularJS HTTP backend for more info (lines 41 - 54 are relevant).
If you are returning a function, you might just need to return true or something after the call.
Edit: After looking at your plunker it seems that your JSONP response is not calling the callback method. The response should be angular.callbacks._0( { ... } ); where { ... } is your object, and angular.callbacks._0 is the value of the callback query parameter in the request.

Your example above is almost right. Just change the callback parameter to
jsoncallback=JSON_CALLBACK
You should have something like that at the end
$http.jsonp(url + '?jsoncallback=JSON_CALLBACK').success(function(data) {
console.log(data);
})

Related

Synchronous AngularJS $http Call

I have an service in my Angular app that is responsible for authorizing the user and returning the auth token back.
However, due to the async nature of $http, I cannot properly isolate the logic of my service. Instead I must return a promise and push the logic of interpreting the response to the caller of the service (single responsibility red flag).
Given this, it's made me reconsider whether I am thinking about this correctly. I come from a Java world where the majority of interactions are synchronous, so something isn't sitting well with me as I try to architect a clean design with single responsibility.
What am I missing here?
UPDATE
I realize the below will not work as intended, but that's my thought of how I'd like it to work at least:
app.service('AuthenticationService', ['$http', '$httpParamSerializerJQLike', function($http, $httpParamSerializerJQLike)
{
this.authServerBaseURL = "...";
this.clientId = "...";
this.authenticate = function(username, password)
{
var config =
{
headers:
{
"Content-Type" : 'application/x-www-form-urlencoded',
"Authorization" : "Basic " + btoa(this.clientId + ":")
}
}
var body = $httpParamSerializerJQLike(
{
grant_type : "password",
username : username,
password : password
});
return $http.post(this.authServerBaseURL + '/oauth/token', body, config).
success(function(data, status, headers, config)
{
return data.access_token;
}).
error(function(data, status, headers, config)
{
return false;
});
}
}]);
Update after you added code: Your thought process can work, see below. However, $http docs say not to use .success and .error. If you instead use .then, as in my examples below, it will work.
Assuming your code is something similar to this:
// AuthService
this.authenticate = function() {
return $http.post('http://example.com', body, config);
}
// Using it:
AuthService.authenticate().then(function(data) {
var token = data.access_token;
});
You can move the knowledge about how the data is extracted to the service like this:
// AuthService
this.authenticate = function() {
return $http.post('http://example.com', body, config).then(function(data) {
return data.access_token;
});
}
// Using it:
AuthService.authenticate().then(function(token) {
var token = token;
});
what happens here is that you make a new promise by calling .then on the $http promise, which is what is returned. The promises are chained, so the $http promise will resolve this new promise, which then resolves itself with the extracted token.

Can't get only the header in AngularJS (v1.3.15) using $resource and method 'HEAD'

In Angular (v1.2.19), I was able to do something like this in a factory :
myApp.factory('GetNumber', ['$resource',
function($resource) {
var get_headers = $resource('some/url', null, {
get_number: {
method: 'HEAD',
transformResponse: function(data, headers) {
var count = headers()['x-number'];
return count;
}
}
});
return get_headers;
}
]);
Call it from my controller like this:
$q.all({
'item1': GetNumber.get_number().$promise,
'item2': SomeOtherService.get().$promise
})
.then(function(results) {
$scope.newNumber = results.item1.value;
});
And I could get the custom header back without having to retrieve the whole header.
Now in v1.3.15, it doesn't work. I can see the header in Chrome with 'x-number' in the header, but if I put a breakpoint in Chrome on the 'var count' line, I never hit it (and I do hit it with v1.2.19).
I've verified that using $http.head works, so if I have this in my controller:
$http.head('some/url')
.success(function(data, status, headers, config) {
var count = headers()['x-number'];
$scope.newNumber = count ? count : 0;
});
I get my scoped value.
I've noticed that there aren't a whole lot of examples of people using the http 'HEAD' method and I'm wondering if there's a reason that I haven't located yet through searching?
I did find this StackOverflow question and answer HTTP Get: Only download the header? (HEAD is not supported) and while I agree with the statement, I don't want the overhead of requesting the headers and the body.
Any suggestions please?
Julie
Thank you to Kevin for suggesting that I use an error handler. I should've thought to try that myself, but I didn't.
Anyway, that lead me to the answer to my problem. To try and catch an error in $resource, it's suggested you use interceptors. I've never used them before and I utilized AngularJS documentation (https://docs.angularjs.org/api/ng/service/$http#interceptors) and changed the code in my factory to be:
myApp.factory('GetNumber', ['$resource',
function($resource) {
var get_headers = $resource('some/url', null, {
get_number: {
method: 'HEAD',
interceptor: { response: function(response) {
var count = response.headers()['x-number']:
return count ? count : 0;
}, responseError: function(rejection) {
console.log('rejection: ', rejection);
}}
}
});
return get_headers;
}
]);
I'm still not sure why transformResponse stopped working and I now need to use interceptor, but very happy I don't have to request the whole body now!
Julie

HTTPInterceptor in AngularJS

We have APIs which returns errors inside the reponse XMLs instead of rejecting them and sending error responses.
So I have the following code to handle them,
$http({
url: apiURL,
method: "POST",
data: req,
headers: oHeaders,
dataType: "xml",
})
.success(function(data,status) {
console.log('success!!!!!');
deff.resolve(data);
})
.error(function(data,status) {
console.log('This is what I want to see!!!!!');
deff.reject(data);
});
myApp.factory('customHttpInterceptor', ['$q', function ($q) {
return function (promise) {
return promise.then(function (response) {
var parsed;
if (response.config.dataType == 'xml'){
parsed = $.xml2json(response.data);
if (parsed) {
angular.forEach(parsed, function(v, k) {
if (k == 'status') {
if (v.APIErrors) {
return $q.reject(response);
}
}
});
}
console.log(parsed);
}
return response;
}, function (errResponse) {
// do something on error
console.log('Error section in interceptor');
return $q.reject(errResponse);
});
};
}]);
What I expected to get from is that when an error is identified within the interceptor it will reject the promise and the control would get into the error section of the $http and log the "This is what I want to see!!!!!" message. But instead is show the "success!!!!!" message.
Is this the way it works or am I doing something wrong?
Ish
I see several things that seem wrong here :
Returning a result in forEach
angular.forEach(parsed, function(v, k) {
if (k == 'status') {
if (v.APIErrors) {
return $q.reject(response);
}
}
});
You probably wrote this because you're used to put return statements inside for loops. This does not work here, because you're returning from inside a function body. There is never any reason to return something in a forEach body function: this value is not going to be used by anything.
Angular Interceptor API
Maybe you just didn't show it in your code, but you have to register your interceptor.
$httpProvider.interceptors.push('customHttpInterceptor');
What's more, your interceptor does not have the correct form : in your case, it should be a object with a response method that returns a promise of a response from a response.

$http and promises and POST

Given code like the following:
function webCall() {
return $http({ method: "POST",
url: "http://destined/to/fail", data: {param1: 1})
.success(function(data, status) { return { test: "success!";} } )
.error(function (data, status) {
return {errorMessage: "Totally failed!"};
});
It is my understanding that if I call .then() on the returned promise like so:
var myPromise = webCall().then(
function(response){
console.log(response.test);
},
function(reason) {
console.log(reason.errorMessage);
});
that the returned value from the appropriate .success() and .error() callbacks is passed along to the .then() callbacks.
I am not seeing the behavior I expect however. Using GET it works as expected. With POST, not so much. Is my assumption that it should act like normal deferred \ promise accurate? Where is it documented (other than the source)
$http() returns a promise, but what you're returning is actually the result of .error(), which isn't a promise (at least it's not documented as such).
To return a promise, you have use then()...
function webCall() {
return $http({ method: "POST",
url: "/destined/to/fail", data: {param1: 1})
.then(function(response) {
// if you need to access the data here, use response.data
return { test: "success!" };
}, function (response) {
throw { errorMessage: "Totally failed!" };
});
}
Note the use of throw to reject the returned promise, because if you simply return from the error callback, it actually resolves resulting promise.
The reason it doesn't work as you expect is because the .success and .error handlers return the original promise and it does nothing with the return value from the success/error handlers. You can see that from the source code for $http here.
promise.success = function(fn) {
promise.then(function(response) {
fn(response.data, response.status, response.headers, config);
});
return promise;
};
You can see that once the promise is resolved (when the web call returns), it will call your sucess handler, and then do nothing with it.
When you chain this with other handlers it is the result of the original promise that is passed along to the other handlers.

Exception handling with jsonp requests in angularjs

I have the following code which make seperate requests for jsonp data.
In the code "doRequestA" works fine and returns a result. The issue I have is
I need to catch any errors if they occur. I have tried implementing this in
"doRequestB", but only receive the alert error (I have ommitted the callback from doRequestB).
Here is the fiddle http://jsfiddle.net/a4Rc2/417/
function jsonp_callback(data) {
alert(data.found);
}
function jsonp_example($scope, $http) {
$scope.doRequestA = function () {
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=jsonp_callback";
$http.jsonp(url);
};
$scope.doRequestB = function () {
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts";
$http.jsonp(url)
.success(function (data) {
alert(data.found);
}).error(function (data, status, headers, config) {
alert('error');
});
};
}
Any advice is greatly appreciated, thanks in advance.
You actually are using $http.jsonp incorrectly in both cases. You just can't see the error in the first case because you are not handling it.
With Angular.js's $http.jsonp method, the callback method is handled automatically. You shouldn't use your own methods in the result string, but rather insert JSON_CALLBACK (exactly as written) into your string. This way, you can handle the response using the promise returned from Angular. If you watch the network activity (say, using Firebug or the developer tools in your browser of choice), you'll see JSON_CALLBACK replaced with something like angular.callbacks._0*.
In the second example, you don't have a callback method defined at all, so the result will always error. There's actually no way for the jsonp result to be handled, since it simply returns the JSON object without a callback method, and the result just is ignored.
Here's a working result: http://jsfiddle.net/tPLaN/1/
The code:
function jsonp_callback(data) {
alert(data.found);
}
function jsonp_example($scope, $http) {
$scope.doRequestA = function() {
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=JSON_CALLBACK";
$http.jsonp(url).success(function(data) {
jsonp_callback(data);
});
};
$scope.doRequestB = function() {
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=JSON_CALLBACK";
$http.jsonp(url)
.success(function (data) {
alert(data.found);
}).error(function (data, status, headers, config) {
alert('error');
});
};
}
The only thing I changed was
Correcting the two URLs.
Moving the callback handler on the first method inside the .success() method on the promise.
Believe it or not, the need for JSON_CALLBACK is in the documentation for $http.jsonp, but it's sort of hidden.
* Note, please do not use the replacement for JSON_CALLBACK for anything. It's a private method generated by Angular, I am just showing it to help make more sense of what is happening.

Resources