Angularjs $resource query method working but get method not working - angularjs

Here is my factory method:
.factory('lettersFactory', ['$resource', function ($resource) {
var url = "";
if(ionic.Platform.isAndroid()){
url = "/android_asset/www/";
}
return $resource(url + 'data/letters.json');
}])
And here is the controller:
.controller('LettersCtrl', ['$scope','lettersFactory', '$stateParams', '$state', '$ionicPopover', function($scope, lettersFactory, $stateParams, $state, $ionicPopover) {
$scope.letters = lettersFactory.query();
$scope.letter = lettersFactory.get({number:parseInt($stateParams.letterId, 10)});
}])
And here is the Error message:
Error in resource configuration for action object. Expected response to contain an array but got an GET (Request: data/letters.json {4})
And my letter.json is an array like this:
[
{"number":1,
"title": "title",
"content": "content"},
{"number":1,
"title": "title",
"content": "content"}
]
Thanks

If the response should not be an array then you need set the isArray as false in query property.
'query': {method: 'GET', isArray: false }
Refer to the document.https://docs.angularjs.org/api/ngResource/service/$resource
Or you can pass the json as array from the controller.

The default method set for $resource contains these actions1:
{ 'get': {method:'GET'},
'save': {method:'POST'},
'query': {method:'GET', isArray:true},
'remove': {method:'DELETE'},
'delete': {method:'DELETE'} };
In your case the get method is failing because the data from the XHR is an array and the method expects an object.
The query method succeeds because the data from the XHR is an array and the method expects an array.
Use the get method for object data; use the query method for array data.
Update
how do you think I can use the query method in this situation to get a particular object from the array data?
One approach is to use the $promise property of the returned resource object:
$scope.array = lettersFactory.query();
$scope.array.$promise.then(function(resourceArray) {
$scope.item = resourceArray[0];
});
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data.
The Resource instances and collections have additional properties:
$promise: the promise of the original server interaction that created this instance or collection.
On success, the promise is resolved with the same resource instance or collection object, updated with data from server.
On failure, the promise is rejected with the http response object, without the resource property.
For more information, see AngularJS $resource API Reference

Related

How do I call $resource service from controller in angularJs

This is get service function where I am calling the API
.factory('Report', function($resource, API_URL) {
return $resource(API_URL +
'security/:userId/1498780800000/listOfDeliveries', {
userId : '#userId',
expected : '#expected',
arg1 : '#arg1'
}, {
update: {
method: 'PUT'
}
});
})
In the app.js I have this below controller
.controller('ReportsController', function($scope, $rootScope,
ProfileData, $state, $timeout, Report) {
})
First of all, you need to check how angular factory & service work.
Your factory return a $resource, so read the doc about $resource
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'}
};
So, you can use theses methods: Report.get(), Report.save(), Report.query(), Report.remove(), Report.delete()
In addition there are custom method you defined: Report.update()
And you can pass userId as params so:
Report.get({userId: 1234}); will call a GET request to: API_URL+'security/1234/1498780800000/listOfDeliveries
(expected and args1 are not in url so I dont think you need them)
What's returning Report.get() ?
Class actions return empty instance (with additional properties below). Instance actions return promise of the action
So Report.get(...) is returning a promise, you will get data by:
Report.get(...).then(function(data) {
$scope.requestData = data;
});

$resource:badcfg Error in resource configuration for action `query`. Expected response to contain an object but got an array

I have following Service, the query always returns an array.
.factory('ClosingDocService', ['$resource', function ($resource) {
return $resource("http://localhost:5001/api/ClosingDoc/:id",
{ id: "#id" },
{
'query': { method: 'GET' },
'save': { method: 'POST', transformRequest: angular.identity, headers: { 'Content-Type': undefined } }
});
}])
However, the following call always got the error?
ClosingDocService.query({ category: model.category }).$promise
.then(function (x) { });
Using fiddler shows the following correct url has been called and the values were returned.
http://localhost:5001/api/ClosingDoc?category=XXX
Error:
angular.js:13920 Error: [$resource:badcfg] Error in resource configuration for action query. Expected response to contain an object but got an array
I found a solution - adding isArray: true. But why?
'query': { method: 'GET', isArray: true },
This occurs due to how $resource object methods are handled.
From the docs on $resource:
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data. This is a useful trick since usually the resource is assigned to a model which is then rendered by the view. Having an empty object results in no rendering, once the data arrives from the server then the object is populated with the data and the view automatically re-renders itself showing the new data. This means that in most cases one never has to write a callback function for the action methods.
Essentially, unless you provide isArray: true, the $resource object method pre-allocates an Object for the data that is to be returned. When the data being returned actually ends up being an array, that data can't be populated into the pre-allocated object.
I had the same issue too. What worked for me was the following fix
Changing the query to get as follows:
ClosingDocService.get({ category: model.category }).$promise
.then(function (x) { });

Angular $resource: object id lost using POST with custom methods

I want to use a custom method in my Foo Factory with a POST call. When I call it as a GET request, it works, but it's deny by my api because it doesn't allow GET for that method.
Request: GET /api/foo/272ee694-b517-4012-b740-98f76973091d/custom_method/ 405
When I change the method to POST (in the angular factory), the object id disapears:
Request: OPTIONS /api/foo/custom_method/ 174
Request: POST /api/foo/custom_method/ 405
Note that this time an OPTION request is made before without the id.
My factory looks like:
appService.factory('foo', ['$resource', 'appConfig',
function($resource, appConfig){
var api_path = appConfig.api_path;
return $resource(api_path + 'foos/:fooId/', {fooId:'#id'},{
query: {
method: 'GET',
isArray: false
},
customMethod: {
method: 'POST',
url: api_path + 'foos/:fooId/custom_method/'
}
});
}]);
And my controler:
$scope.foo = foo.get({fooId: $routeParams.fooId});
$scope.customMethod = function() {
foo.customMethod({fooId:$scope.foo.id});
}
Anyone could help me? Thank you in advance
So, I found the solution. In the controller, just call custom_method from the object with a $. Like this:
$scope.foo.$custom_method();
You can also omit to pass the id because $resource get it from the object by default.

How to output json data in controller in angularjs

I am learning angularjs and i want to ouput some json data on console.
I am doing something like this
$scope.events = events.query();
but when i print on the console
console.log($scope.events);
it gives me the output like
Array []
how can i print the data like this
[
{"id":18,"file":{"url":"/uploads/playlist/file/18/01_-_MashAllah.mp3"},"event_id":23,"created_at":"2015-11-11T10:33:52.000Z","updated_at":"2015-11-11T10:33:52.000Z","name":"01 - MashAllah.mp3"},
{"id":19,"file":{"url":"/uploads/playlist/file/19/02_-_Laapata.mp3"},"event_id":19,"created_at":"2015-11-11T10:50:01.000Z","updated_at":"2015-11-11T10:50:01.000Z","name":"02 - Laapata.mp3"}
]
below is my whole code
.controller('ShowEventsCtrl', ['$scope','events', function($scope,events) {
$scope.events = events.query();
console.log($scope.events);
}]);
services
angular.module('myApp')
.factory('events', ['$resource',function($resource) {
return $resource('/events', {},{
query: { method: 'GET', isArray: true },
create: { method: 'POST' }
})
}])
and when i print the data in html like this
<div ng-repeat="playlist in playlists">
{{playlist}}
</div>
I get the correct output so i but how to output it in console.
Because your events.query() method is asynchronous, you need to log stuff after the action is resolved. Easiest way I can think of is
$scope.events = events.query(function(events) {
console.log(events);
});
From $resource
The action methods on the class object or instance object can be invoked with the following parameters:
HTTP GET "class" actions: Resource.action([parameters], [success], [error])
...
Success callback is called with (value, responseHeaders) arguments
I'm guessing your confusion comes from this feature of $resource
It is important to realize that invoking a $resource object method immediately returns an empty reference (object or array depending on isArray). Once the data is returned from the server the existing reference is populated with the actual data.
You see the correct data in your template because once the data is returned from the server, a scope digest is triggered and your template is updated.

AngularJS: Resource factory and callback function

Hi being new to Angular i'm having difficulty seeing how to handle data when using $resource in a factory. I'm trying to move from $http requests to $resources in my factory.
First i had (simplified code):
.factory('MetadataService', function($http) {
$http({
method: 'OPTIONS',
url: 'http://myurl'
}).success(function(data) {
customized_data = do_some_complex_handling_on_data(data)
callback(customized_data);
});
});
When i try to use a $resource in my factory, it seems that i have to call the do_some_complex_handling_on_data() method in my controller:
.factory('MetadataService', function($resource) {
return($resource('http://myurl', {}, {
metadata: {method: 'OPTIONS'}
}));
});
# controller:
var metadata = do_some_complex_handling_on_data(MetadataService.metadata());
Since i'm gonna use the factory in a lot of controllers for different sections in my application (that's why i made a factory in the first place), i would like to have my factory return the data as i need it. And not have to customize the data after the factory returns it.
question: How do i let my factory call the do_some_complex_handling_on_data() function instead of the controller?
You can use response transformer that $http service provides. A transformer is used to transform the response of $http before it is delivered to the end client.
By default there is a single transformer register that convert json string to json object. You can append your own transformer to this collection and it will be called with the response json object. In your transformer function you can then call any function you want that can transform the data.
metadata: {
method: 'OPTIONS'
transformResponse: appendTransform($http.defaults.transformResponse,
function(value) {
return do_some_complex_handling_on_data(value);
})
}
function appendTransform(defaults, transform) {
// We can't guarantee that the default transformation is an array
defaults = angular.isArray(defaults) ? defaults : [defaults];
// Append the new transformation to the defaults
return defaults.concat(transform);
}
I have taken this code from the docs here
Also read documentation on "Default Transformations" in $http service

Resources