I'm working with an API that follows the JSON API spec.
http://jsonapi.org/
I'm building an app in Ionic using ngResource, and the resource.query() method expects the response to be an array:
[
{
"id": 1,
"foo": "bar"
},
{
...
}
]
But the JSON API spec passes that nested under the data attribute:
{
"data": [
{
"id": 1,
"foo": "bar"
},
{
...
}
]
}
How can I automatically post-process the response from the API to fulfill what ngResource is expecting?
Look into transformResponse and interceptor objects.
https://docs.angularjs.org/api/ngResource/service/$resource
EDIT: Adding code
$provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
return {
'response': function(response) {
response.data = response.data.data;
return response;
}
};
});
$httpProvider.interceptors.push('myHttpInterceptor');
EDIT:
As you can see below, the query method is built to handle arrays by default.
{ 'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'}
};
you can use simple GET method to get object list response from your api.
OR you can change query default behavior to this way.
:
var config = { method:'GET', isArray: false };
var url = 'http://jsonapi.org';
$resource(url, {}, {query: config});
for more detail. Please check https://docs.angularjs.org/api/ngResource/service/$resource
Related
user.json File has just one entry:
{
"id": 1,
"protocol": "http",
"ip": "255.255.255.0",
"port": "80",
"userName": "usemanager",
"password": "password",
"diskPath": "D:nwjs"
}
Factory Code:
duseApp.factory('duseConnect', function ($resource) {
return $resource("user.json");
});
Controller Code:
duseApp.controller("duseLoginController", function ($scope,duseConnect,
$location) {
var user = duseConnect.get({id: 1});
console.log(user);
console.log(user.id);
});
User Gets Listed.
But console.log(user.id); is undefined.
Why is it so?
OutPut of console.log(user);
output
It looks like your factory is returning promise and in that case you need to extract data from the promise.
duseConnect.get({id: 1}).then (function(user) {
console.log(user);
console.log(user.id);
});
The return of $resource is a resource "class" object with methods for the default set of resource actions optionally extended with custom actions. The default set contains these actions:
{ 'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'}
};
The way of using it could be:
var User = $resource('/user/:userId', {userId:'#id'});
var user = User.get({userId:123}, function() {
user.abc = true;
user.$save();
})
In your case you can do something like:
duseApp.controller("duseLoginController", function ($scope,duseConnect,
$location) {
var user = duseConnect.get({id: 1}, function (response) {);
console.log(response);
console.log(response.id);
}});
I try to get response data from angular service created by factory and $resource. I want to send POST request to server to create object in db and received created ID.
So I create service like this:
angular.module('sample')
.factory('Client', function ($resource) {
return $resource('api/clients/:id', {}, {
'query': { method: 'GET', isArray: true},
'get': {
method: 'GET',
transformResponse: function (data) {
data = angular.fromJson(data);
return data;
}
}
});
});
I use Client service in controller:
$scope.create = function () {
Client.save($scope.client,
function (response) {
$state.go("clientDetail", {'id' : whereIsMyId.id? })
});
};
Unfortunately, I do not know how to read data in response.
As response I just get number like "6" but this could be any JSON.
Thank you.
How do i get the get JSON data out of a $resource?
Currently all return values out of User.query and User.$save() are factory objects. I would like to be able to keep $scope.users as raw JSON so I can modify it and post the data to another URL.
myApp.factory("User", function($resource) {
return $resource("/api/users/:Id", { Id: "#Id"}, {
"update": {method:"PUT"},
"query": { method:"GET", isArray: true }
});
});
var users = User.query(function() {
$scope.users = users;
});
You can transform the response like this:
myApp.factory("User", function($resource, $http) {
return $resource("/api/users/:Id", { Id: "#Id"}, {
"update": {method:"PUT"},
"query": {
method:"GET",
isArray: true,
transformResponse: [function (data, headersGetter) {
return [{ result: JSON.parse(data) }];
}].concat($http.defaults.transformResponse)
}
});
});
My code: http://plnkr.co/edit/2blxwwyv0gS9GYui7IVn?p=preview
I defined a service:
angular.module('jsonService', ['ngResource']).factory('JsonService', function($resource) {
var jsonService = $resource('data.json/:id',
{id: "#id"}, //parameters default
{
getAll: { method: "GET", params: {} },
addNew: { method: "POST", params: { id: ":id"}},
});
return jsonService;
});
I keep getting error when I try to call getAll from my controller.
I also tried to add a new object but AddNew simply would not work from the controller.
Add isArray: true
getAll: { method: "GET", params: {}, isArray: true },
Please take a look at actions parameter from $resources.
isArray – {boolean=} – If true then the returned object for this
action is an array, see returns section.
And this is how to post data
non-GET "class" actions: Resource.action([parameters], postData,
[success], [error])
For example:
var obj = { "id": "2", "created": "3424324", "updated": "2342666", "name": "Bob" };
JsonService.addNew({ "id": "2"}, obj)
$resource is awesome providing very convenient way to handle web services.
What if GET and POST have to be performed on different URLs?
For example, GET URL is http://localhost/pleaseGethere/:id
and POST URL is http://localhost/pleasePosthere without any parameter
Use 'url' property of [actions] to override the default url.
$resource(url, [paramDefaults], [actions], options);
for example:
$resource('http://localhost/pleaseGethere/:id',{},{
getMethod:{
method:'GET',
isArray:true
}
postMethod:{
url:'http://localhost/pleasePosthere',
method:'POST',
isArray:false
}
}
Usage of Angular $resource: http://docs.angularjs.org/api/ngResource/service/$resource
You should be able to expose the URL as a parameter. I was able to do this:
$provide.factory('twitterResource', [
'$resource',
function($resource) {
return $resource(
'https://:url/:action',
{
url: 'search.twitter.com',
action: 'search.json',
q: '#ThingsYouSayToYourBestFriend',
callback: 'JSON_CALLBACK'
},
{
get: {
method: 'JSONP'
}
}
);
}
]);
Then you can overwrite the URL on your GET call.
The one caveat I found during my REALLY brief testing was that if I included http:// in the URL string, it didn't work. I didn't get an error message. It just did nothing.
If you add the hash with param names into the $resource call:
$resource('localhost/pleaseGethere/:id', {id: '#id'});
Then the :id will be mapped to id param when invoking the function (this will call GET localhost/pleaseGethere/123):
Resource.get({id: 123});
For POST, you simply don't assign the id param:
Resource.post({}, {name: "Joe"});
The proper URL will be called, which is in this case POST localhost/pleaseGethere (the trailing slash is stripped by ngResource).
See http://docs.angularjs.org/api/ngResource.$resource -> Examples -> Credit card resource for more details.
In addition to Iris Wong's answer, I wanted to give an example of having multiple params with multiple methods and actions:
angular
.module('thingApp')
.factory('ThingResource', ['$resource', '$state', returnThing]);
And the resource:
function returnThing($resource, $state) {
var mainUrl = '/api/stuffs/:stuffId/thing'
var params = {stuffId: '#_id', thingMongoId: '#_id', thingNumber: '#_id'}
return $resource(mainUrl, params, {
'save': {
url: '/api/stuffs/:stuffId/thing/:thingMongoId',
method: 'POST',
interceptor: {
responseError: function(e) {
console.warn('Problem making request to backend: ', e)
$state.go('oops')
}
}
},
'get': {
url: '/api/stuffs/:stuffId/thing/:thingMongoId',
method: 'GET',
interceptor: {
responseError: function(e) {
console.warn('Problem making request to backend: ', e)
$state.go('oops')
}
}
},
'assignThing':{
method: 'POST',
url: '/api/stuffs/:stuffId/thing/assign/:thingNumber'
}
});
}
Which gives 3 separate methods:
// POST to http://currnt_base_url/api/stuffs/:stuffId/thing/:thingMongoId
ThingResource.save({
stuffId:'56c3d1c47fe68be29e0f7652',
thingMongoId: '56c3d1c47fe6agwbe29e0f11111'})
// GET to current http://currnt_base_url/api/stuffs/:stuffId/thing/:thingMongoId
ThingResource.get({
stuffId:'56c3d1c47fe68be29e0f7652',
thingMongoId: '56c3d1c47fe6agwbe29e0f11111'})
// POST to http://currnt_base_url/api/stuffs/:stuffId/thing/assign/:thingNumber
ThingResource.assignThing({
stuffId:'56c3d1c47fe68be29e0f7652',
thingNumber: '999998'})
Follow this way:
(function () {
'use strict';
angular
.module("app")
.factory("SomeFactory", SomeFactory);
function SomeFactory($resource) {
var provider = "http://stackoverflow.com/:action/:id";
var params = {"id":"#id"};
var actions = {
"create": {"method": "POST", "params": {"action": "CreateAwesomePost"}},
"read": {"method": "POST", "params": {"action": "ReadSomethingInteresting"}},
"update": {"method": "POST", "params": {"action": "UpdateSomePost"}},
"delete": {"method": "GET", "params": {"action": "DeleteJustForFun"}}
};
return $resource(provider, params, actions);
}
})();
I hope it help! Enjoy!