parsing JSONP $http.jsonp() response in angular.js - javascript

I am using angular's $http.jsonp() request which is successfully returning json wrapped in a function:
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=jsonp_callback";
$http.jsonp(url).
success(function(data, status, headers, config) {
//what do I do here?
}).
error(function(data, status, headers, config) {
$scope.error = true;
});
How to access/parse the returned function-wrapped-JSON?

UPDATE: since Angular 1.6
You can no longer use the JSON_CALLBACK string as a placeholder for
specifying where the callback parameter value should go
You must now define the callback like so:
$http.jsonp('some/trusted/url', {jsonpCallbackParam: 'callback'})
Change/access/declare param via $http.defaults.jsonpCallbackParam, defaults to callback
Note: You must also make sure your URL is added to the trusted/whitelist:
$sceDelegateProvider.resourceUrlWhitelist
or explicitly trusted via:
$sce.trustAsResourceUrl(url)
success/error were deprecated.
The $http legacy promise methods success and error have been deprecated and will be removed in v1.6.0. Use the standard then method instead. If $httpProvider.useLegacyPromiseExtensions is set to false then these methods will throw $http/legacy error.
USE:
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts"
var trustedUrl = $sce.trustAsResourceUrl(url);
$http.jsonp(trustedUrl, {jsonpCallbackParam: 'callback'})
.then(function(data){
console.log(data.found);
});
Previous Answer: Angular 1.5.x and before
All you should have to do is change callback=jsonp_callback to callback=JSON_CALLBACK like so:
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=JSON_CALLBACK";
And then your .success function should fire like you have it if the return was successful.
Doing it this way keeps you from having to dirty up the global space. This is documented in the AngularJS documentation here.
Updated Matt Ball's fiddle to use this method: http://jsfiddle.net/subhaze/a4Rc2/114/
Full example:
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=JSON_CALLBACK";
$http.jsonp(url)
.success(function(data){
console.log(data.found);
});

The MOST IMPORTANT THING I didn't understand for quite awhile is that the request MUST contain "callback=JSON_CALLBACK", because AngularJS modifies the request url, substituting a unique identifier for "JSON_CALLBACK". The server response must use the value of the 'callback' parameter instead of hard coding "JSON_CALLBACK":
JSON_CALLBACK(json_response); // wrong!
Since I was writing my own PHP server script, I thought I knew what function name it wanted and didn't need to pass "callback=JSON_CALLBACK" in the request. Big mistake!
AngularJS replaces "JSON_CALLBACK" in the request with a unique function name (like "callback=angular.callbacks._0"), and the server response must return that value:
angular.callbacks._0(json_response);

This was very helpful. Angular doesn't work exactly like JQuery. It has its own jsonp() method, which indeed requires "&callback=JSON_CALLBACK" at the end of the query string. Here's an example:
var librivoxSearch = angular.module('librivoxSearch', []);
librivoxSearch.controller('librivoxSearchController', function ($scope, $http) {
$http.jsonp('http://librivox.org/api/feed/audiobooks/author/Melville?format=jsonp&callback=JSON_CALLBACK').success(function (data) {
$scope.data = data;
});
});
Then display or manipulate {{ data }} in your Angular template.

This should work just fine for you, so long as the function jsonp_callback is visible in the global scope:
function jsonp_callback(data) {
// returning from async callbacks is (generally) meaningless
console.log(data.found);
}
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts?callback=jsonp_callback";
$http.jsonp(url);
Full demo: http://jsfiddle.net/mattball/a4Rc2/ (disclaimer: I've never written any AngularJS code before)

You still need to set callback in the params:
var params = {
'a': b,
'token_auth': TOKEN,
'callback': 'functionName'
};
$sce.trustAsResourceUrl(url);
$http.jsonp(url, {
params: params
});
Where 'functionName' is a stringified reference to globally defined function. You can define it outside of your angular script and then redefine it in your module.

For parsing do this-
$http.jsonp(url).
success(function(data, status, headers, config) {
//what do I do here?
$scope.data=data;
}).
Or you can use
`$scope.data=JSON.Stringify(data);
In Angular template you can use it as
{{data}}

for me the above solutions worked only once i added "format=jsonp" to the request parameters.

I'm using angular 1.6.4 and answer provided by subhaze didn't work for me. I modified it a bit and then it worked - you have to use value returned by $sce.trustAsResourceUrl. Full code:
var url = "http://public-api.wordpress.com/rest/v1/sites/wtmpeachtest.wordpress.com/posts"
url = $sce.trustAsResourceUrl(url);
$http.jsonp(url, {jsonpCallbackParam: 'callback'})
.then(function(data){
console.log(data.found);
});

Related

Problems getting data using AngularJS

I'm just learning Angular JS.
I'm trying to populate the scope variable with the result of an ajax database call.
The ajax call returns a propper json object(an array) but I cannot get $scope.contentType to output on my HTML page.
Can anyone see any reason this should not work?
app.controller('MainController', ['$scope', function($scope){
var allMyData;
$scope.title = 'Content Types List';
var request = $.ajax({
type: "POST",
dataType: "json",
url: "/angularJS/dbServices.cfc?method=getContentTypes"
})
request.done(function(data){
allMyData = data.DATA;
console.log(allMyData);
$scope.contentTypes = allMyData;
})
request.fail(function(){
console.log('fail');
})
}])
The reason your $scope isn't updating on the view is because you are changing that value outside the $digest cycle. You need to use AngularJS' built-in $http service.
You can get more information/documentation in the link above.
It is because you are using jQuery ajax which is not triggering angular digest. You can fix it with:
request.done(function(data){
$scope.apply(function() {
allMyData = data.DATA;
console.log(allMyData);
$scope.contentTypes = allMyData;
})
})
However, this is not the best practice. Instead you should 1) use $http service as mentioned in other answer 2) Move the entire logic to a separate service 3) use a high-level interface provided by ngResource

$Resource error - when using $save.success callback but data is saving OK

I'm trying to use a resource to save some data, and am getting something strange happen:
here is the code:
var appointment = new Appointment(formData);
console.log(appointment);
appointment.$save().success(function (data, status, headers, config){
console.log(data);
$state.transitionTo('form.success');
});
now the wierd thing is that the data is saving so the $save function is working, but I'm getting undefined is not a function errors, and the success callback isnt working - does anyone know why?
The resource for the Appointments is:
angular.module('MyApp')
.factory('Appointment', function($resource){
return $resource('/api/admin/:id', { id: "#_id" }, {
query: {method:'GET', isArray:true}
});
})
and I'm using this and its inherent $save function, so it shouldn't be a problem - also it seems to be the callback thats not working - the save is adding data no problem
SOLUTION:
I simplified it by just doing:
appointment.$save(function(data){
//stuff here for the callback works
});
also I think that using the promise method .then would work, but I didn't try it.
I marked it as accepted anyway for good karma!
Thanks
The success function is specific to the $http service:
The $http service is a function which takes a single argument — a configuration object — that is used to generate an HTTP request and returns a promise with two $http specific methods: success and error.
The $save method returns a regular promise, so you can use then instead:
appointment.$save().then(function (data, status, headers, config){
console.log(data);
$state.transitionTo('form.success');
});

AngularJS HTTP Resource - Response Function Undefined

I'm using an Angular HTTP Resource to get some data from an API. The method on the API is actually a PUT, but returns an array of data. (Note, it's not my API)
It performs the HTTP Call perfectly and I can see in the Network on Google Developer Tools my response is right. However, I keep getting "TypeError: undefined is not a function" when trying to work with the response data.
Here are some of the different methods I've tried and each one gives the same TypeError:
HTTP Resource
.factory('Sports', ['$resource', 'SPORTS_CONFIG',
function($resource, SPORTS_CONFIG) {
return $resource(SPORTS_CONFIG.URL, {}, {
get: {
method: 'PUT',
isArray: true
}
});
}
])
Angular JS Attempts
// Construct Sports Body
var s = new Sports($scope.sport);
// Attempt 1
s.$get({}, function(data){
});
// Attempt 2
s.$get({}).then(function(data){
});
// Attempt 3
s.$get({}).$promise.then(data){
});
EDIT
After looking at my error code more, it looks like the error is occurring on 'isArray' in my HTTP Resource. When I set isArray to false, it errors because it expects an object but gets an array. When I keep it true, it errors and says TypeError: undefined is not a function. When I click the javascript line it's 'isArray'.
SECOND EDIT
I've gotten it to work using the following code:
$scope.teams = Sports.get($scope.sport);
However, $scope.teams = [0, $promise, $resolved] . How can I only get [0] instead of the $promise and $resolved?
the argument to your 'then' function should itself be a function.
eg:
s.$get({}).then(function (data){
});
Your syntax looks wrong, follow this approach instead:
$http.get('/someurl').then(function(response) {
//do something with response.data;
}, function(errResponse) {
console.error('Error while fetching data');
});
As you can see you should be passing in a function which passes in the response from the server, and then you can get at your data.
You can try something like this (with a function)
$http({
method : "GET",
url : "your_url"
}).success(function(data, status, headers, config) {
$scope.yourVariable= data;
}).error(function(data, status, headers, config) {
alert("Request failed. HTTP status:" + status);
});
Due to the edit above, this answer became outdated.
As I cannot comment right now, the way to get the just first item as you'd like is simple:
$scope.teams = Sports.get($scope.sport)[0];

how to get correct JSON object from flickr API

I used flickr photo search method to retrieve public photos.
when I run it with jquery, it works fine, I get the json object in correct form.
{
"photos": {
"photo": [
{
.........
}
]
},
"stat": "ok"
}
But when I use it with AngularJs, I got the same object with a prefix jsonFlickrApi
jsonFlickrApi({
"photos": {
"photo": [
{
......
}
]
},
"stat": "ok"
})
what I used in AngularJs is:
myApp.service('dataService', function($http) {
delete $http.defaults.headers.common['X-Requested-With'];
this.flickrPhotoSearch = function() {
return $http({
method: 'GET',
url: 'https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=3f807259749363aaa29c2fa93945&tags=india&format=json&callback=?',
dataType: 'json'
});
}
});
Please tell me how can I convert the second JSON to the first one.
Is there anything I can do in $http call or have to alter JSON object.
There was problem in the url.
This Url works for me.
https://api.flickr.com/services/rest/?method=flickr.people.getPublicPhotos&api_key=3f807259749363aaa29c712fa93945&user_id=61495424#N00&format=json&nojsoncallback=?
You have to add nojsoncallback=1 to the url, like this
https://api.flickr.com/services/rest/?method=flickr.photos.getRecent&api_key=XXX&format=json&nojsoncallback=1
And that remove the jsonFlickrApi function on response.
The above answer which says to add nojsoncallback=1 is correct, but I'd like to provide more context and reasoning behind it.
If you take a look at the documentation (which is poorly formatted in my opinion): https://www.flickr.com/services/api/response.json.html and scroll all the way to the bottom you will find, tucked away:
Callback Function
If you just want the raw JSON, with no function wrapper, add the parameter nojsoncallback with a value of 1 to your request.
To define your own callback function name, add the parameter jsoncallback with your desired name as the value.
nojsoncallback=1 -> {...}
jsoncallback=wooYay -> wooYay({...});
The key part being: If you just want the raw JSON, with no function wrapper, add the parameter nojsoncallback with a value of 1 to your request
Therefore, add this to your request and it will remove jsonFlickrAPI wrapper that you are seeing in your response: nojsoncallback=1
You are getting a JSONP response (notice the P) which is basically a function call with an argument that is the response you are expecting.
Easy solution for you: Create a function named jsonFlickrApi with a parameter response and you can do your handing in there.
At this point, I am not sure if you can define your function inside your service but try it. If not, you can define it outside.
Alternatively, try using $http.get function instead. Were you specifying the return accepted by the client in your jQuery original code?
EDIT
Try this setting the data type of the request using $http or $http.get without forgetting to specify the data property in the settings object.
$http({
url: 'http://localhost:8080/example/teste',
dataType: 'json',
method: 'POST',
data: '',
headers: {
"Content-Type": "application/json"
}
}).success(function(response){
$scope.response = response;
}).error(function(error){
$scope.error = error;
});

How to make a jsonp request

I need to do some cross site scripting. The block of code below contains the method of jsonp, the method returns as if it failed, but when I change it to be a get request I then have success. I need to be able to a successful response using the jsonp method. The following can be ruled out. The response is valid json and this param is in the url ?callback=JSON_CALLBACK. Here is the json I receive from doing the http request and the code block that executes this code.
http response status code 200
[{"cube":"1" ,"points":"160"},{"cube":"2","points":"690"},{"cube":"3","points":"331"}]
code block
var myApp = angular.module('test', []);
myApp.controller('UserCtrl', function($scope, users) {
$scope.usersPerCube = users.getUsers();
})
myApp.factory('users', function($http) {
return {
getUsers: function() {
var deferred = $q.defer();
var url = "http://localhost/api/api/index.php/analytics/UsersPerCube?callback=JSON_CALLBACK";
$http.get(url).success(function (data, status, headers, config) {
console.log(data);
deferred.resolve(data);
}).error(function (data, status, headers, config) {
//this always gets called
console.log(status);
deferred.reject(status);
});
return deferred.promise;
}
}
Note that I have edited my server side code and now receive
"angular.callbacks._1( {"cube":"1","points":"160"},{"cube":"2","points":"690"},{"cube":"3","points":"331"})"
UPDATE
The above is valid and now the success method is executing. I just need to figure out how to parse the objects. I will post again once I figure out the answer.
I have decided to give a detailed description of how to do a jsonp request so others will not run into the same troubles as I did.
myApp.factory('users', function($http) {
return {
getUsers: function() {
var deferred = $q.defer();
var url = "http://localhost/api/api/index.php/analytics/UsersPerCube?callback=JSON_CALLBACK";
$http.get(url).success(function (data, status, headers, config) {
console.log(data);
deferred.resolve(data);
}).error(function (data, status, headers, config) {
//this always gets called
console.log(status);
deferred.reject(status);
});
return deferred.promise;
}
Notice that the url contains ?callback=JSON_CALLBACK. Here is a nice stackoverflow on that. Once you get the response then you'll receive a json like the one below.
"angular.callbacks._1( {"cube":"1","points":"160"},{"cube":"2","points":"690"},{"cube":"3","points":"331"})"
Here is a nice stackoverflow on that subject
Now the one part that got me is that the server has to return the GET param, callback. Here is a good tutorial for that. http://niryariv.wordpress.com/2009/05/05/jsonp-quickly/ So the json looks like the one above.
Well, I hope this helps someone in the future.
If you want to make several JSONP requests through $http service, you should use a little hack. Agular change JSON_CALLBACK to internal value, and best way to use next solution: put this js code into your returned js-file:
var callbackId = '_' + (angular.callbacks.counter - 1).toString(36);
angular.callbacks[callbackId](/* YOUR JSON */);
To be sure that this code will work for you, please check createHttpBackend method in angular sources.

Categories