ngResource new instance error when call $query - angularjs

Let's say I have a $resource like:
var Collections = $resource("http://somedomain/collections/:action", {
action: "#action"
});
If I create a new instance
var myCollections = new Collections()
When I do
myCollections.$query();
I get this error:
TypeError: value.push is not a function
Now, the response is an array as expected and everything seems to be in order.
If I do
var myCollections = Collections.query();
it works
Any ideas why? What am I doing wrong?

If you're using $resource in that way, I do believe there is no such thing is a $query(), only query() with no dollar sign in front of it. There is a $save() which I think can get pretty confusing.
I wish the documentation was a bit better on this subject, but one way to see all your possible calls on that object is checking under the prototype for when you console.log myCollections. That, and searching examples on the web.

Related

Is it possible to perform a Restangular GET with multiple query parameters?

I've been attempting to perform a Restangular GET with multiple query parameters (for simple pagination) and it doesn't seem possible--at least with what I'm trying to do. Here's what I'm attempting to do:
Restangular.all('elevation').get({ pageParam: page, pageSizeParam: pageSize }).then(function(data) {
console.log(data);
});
WIth the expected response looking something like:
{ totalRecords: 233, elevations: {...} }
This does not work and results in the following:
GET http://localhost:24287/elevation/[object%20Object] 404 (Not Found)
I also attempting utilizing customGET as well which results in the same problem as above.
The only way I'm actually able to pass multiple query parameters is by using getList. Unfortunately when utilizing the getList unsurprisingly the following error is thrown:
Error: Response for getList SHOULD be an array and not an object or something else
To resolve this issue, the Restangular documentation states in the My response is actually wrapped with some metadata. How do I get the data in that case? section that I need to use addResponseInterceptor which I've done like so:
RestangularProvider.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
var newResponse = [];
if(response.data.totalRecords !== undefined) {
newResponse.elevationData= {};
newResponse.elevationData.totalRecords = response.data.totalRecords;
newResponse.elevationData.elevations = response.data.elevations;
}
return newResponse;
});
After jumping through hoops this convoluted solution does in fact work. Is there not an easier way to simply call Restangular's get with multiple query parameters and get an object returned?
At this point, it would be a magnitude easier to take Restangular out of the question and simply use the $http service like so:
$http.get('http://localhost:24287/elevation?page=' + page + '&pageSize=' + pageSize).then(function(result) {
console.log(result.data.totalRecords);
console.log(result.data.elevations);
});
Though I really want to figure out a better way to do this with Restangular.
Any ideas would be greatly appreciated! Thanks!
That's deadly simple, querying a ressource URL without an id, even with specific query params, and returning a single object is just not RESTful.
Error: Response for getList SHOULD be an array and not an object or something else
It's precisely telling you the truth : your query could return an array, because you haven't specified a unique identifier (everything else is not unique).
At this point, it would be a magnitude easier to take Restangular out of the question and simply use the $http service
Definately, since Restangular focuses on RESTful resource proxying, or you're gonna have to tweak it (interceptors, customGET, ...)

Issues with single-requests in Restangular

I'm having a slight issue with my ability to consume REST data retrieved via Restangular in an angular controller. I have the following code which works fine for a list of accounts:
var baseAccounts = Restangular.all('accounts');
baseAccounts.getList().then(function(accounts) {
$scope.accounts = accounts;
});
This works perfectly for a list. I use similar syntax for a single account:
var baseAccount = Restangular.one('accounts');
baseAccount.getList(GUID).then(function(returnedAccount) {
$scope.currentAccount = returnedAccount;
});
I am using ng-repeat as the handling directive for my first request. I am attempting to bind with {{ account.name }} tags for the single request, but it does not seem to display any data despite the request being made properly. GUID is the parameter I must pass in to retrieve the relevant record.
I have combed through Restangular docs and it seems to me like I am composing my request properly. Any insight would be greatly appreciated.
EDIT: I've tried all of the solutions listed here to no avail. It would seem Restangular is submitting the correctly structured request, but when it returns it through my controller it shows up as just a request for a list of accounts. When the response is logged, it shows the same response as would be expected for a list of accounts. I do not believe this is a scoping issue as I have encapsulated my request in a way that should work to mitigate that. So, there seems to be a disconnect between Request -> Restangular object/promise that populates the request -> data-binding to the request. Restangular alternates between returning the array of accounts or undefined.
Have you looked at:
https://github.com/mgonto/restangular#using-values-directly-in-templates
Since Angular 1.2, Promise unwrapping in templates has been disabled by default and will be deprecated soon.
Try:
$scope.accounts = baseAccounts.getList().$object;
try:
var baseAccount = Restangular.one('accounts', GUID);
baseAccount.get().then(function(returnedAccount) {
$scope.currentAccount = returnedAccount;
});
The problem here is that it's expecting an array to be returned. I'm assuming that you are expecting an account object. Thus we need to use the get function, intead of getList()
The one() function has a second argument that accepts an id e.g. .one('users', 1). You can take a use of it.
CODE
var baseAccount = Restangular.one('accounts', 1); //1 would be account id
baseAccount.getList('account').then(function(returnedAccount) {
$scope.currentAccount = returnedAccount;
});
OR
var baseAccount = Restangular.one('accounts', 1); //1 would be account id
baseAccount.all('account').getList().then(function(returnedAccount) {
$scope.currentAccount = returnedAccount;
});
For more info take look at github issue
Hope this could help you, Thanks.

Reading a angularjs promise object?

I have a service that returns a study object as shown:
$scope.study = StudyService.studies.get({id: $routeParams.studyIdentifier});
When I print out the study object using:
console($scope.study);
I get this message on the chrome console:
Resource {$promise: Object, $resolved: false, $get: function, $save: function, $query:
function...}
So how do I read this study object. I like to be able to print its contents. For instance study has an id, and a list of cases. I like to be able to print:
console.log(study.id);
console.log(study.cases.length);
How do I accomplish this?
I assume that since you are receiving a promise as a response from your service you are using 'ngResource'. If so, then here is some documentation on using that module and how to handle the objects it returns.
https://docs.angularjs.org/api/ngResource/service/$resource
For your example though, you would need to just do the following
StudyService.studies.get({id: $routeParams.studyIdentifier}).$promise.then(function(study) {
$scope.study = study;
});
Hope this helps!

Making calls from the Javascript client library with #Named and unnamed parameters makes no sense

I have a Cloud Endpoints method that looks like this:
//HTTP POST
#ApiMethod(name = "hylyts.insert")
public Hylyt insertHylyt(#Named("url") String url, Hylyt hylyt, User user)
throws OAuthRequestException{
log.info("Trying to save hylyt '"+hylyt+"' with id '"+hylyt.getId());
if (user== null) throw new OAuthRequestException("Your token is no good here.");
hylyt.setArticle(getArticleKey(url, user));
ofy().save().entity(hylyt);
return hylyt;
}
I call it from the Javascript Client Library using this:
gapi.client.hylytit.hylyts.insert({PARAMS}).execute(callback);
Now, if I structure {PARAMS} as suggested in the docs (second example),
{
'url': url,
'resource': {
'hylyt': {
'contentType': 'application/json',
'data': hylyt
}
}
}
I get a null object in the endpoint (not to mention that the whole point of this library is to make these calls simple, which this structure clearly violates).
When I structure {PARAMS} as these answers suggest,
{
'url': url,
'resource': hylyt
}
I get a null object in the endpoint again. The correct syntax is this:
{
'url': url,
'id': hylyt.id
'text': hylyt.text
}
Which just blows my mind. Am I doing this all wrong? Is this a bug? Is it only happening because gapi is also passing the auth token in the background?
Yes, I could use the request syntax instead, but, again, why even use the library if it's just as complex as making the XHRs in pure javascript? I wouldn't mind the complexity if Google explained in the docs why things are happening. But the docs, paraphrased, just say use these methods and the auth, CORS, and XHR magic will happen behind closed doors.
Is the API method correctly recognized as POST method?
The resource parameter which is sent as POST body won't work correctly in a GET request.
The way it looks you are actually sending a GET request with the Hylyt properties in the query string.
To make sure you can change the method annotation to this:
#ApiMethod(name = "hylyts.insert", httpMethod = HttpMethod.POST)
Yup, agreed it's a bug. caused me great pains as well.
So i guess the work around is to create a combined object to pass to your api all named and un named parameters. Rather than hardcode each.. a quick loop might be better.
var param = {};
param["url"] = url;
for (var prop in hylyt) {
param[prop] = hylyt[prop];
}
gapi.client.hylytit.hylyts.insert(param).execute(callback);
That mashing together of parameters / objects can become a slick function if you really want.. but it's a band aid for what I'd consider a defect.
I see in the related question (cloud endpoints resource attribute for transmitting named params & body not working), you actually logged a defect.. Good stuff. Though there still appears no movement on this one. fingers crossed for someday!
The bug has been resolved. The correct syntax is
gapi.client.hylytit.hylyts.insert({url: url}, hylyt).execute(callback);

Testing for whether an object is an angularJS $resource

Simple (seeming) question - I'm trying to do a simple sanity check in my AngularJS controller to make sure that my $resource is actually instantiated as such. It's a largish app, but for example:
.factory('AccountSearchService_XHR', ["$resource", function($resource) {
var baseUrl = "http://localhost\\:8081/api/:version/accounts/:accountNumber";
return $resource(baseUrl,
{
version: "#version",
accountNumber: "#accountNumber"
},
{
get: {method: 'GET', isArray: false}
});
}]);
Then later, in controller:
$scope.accountObj.currentAccount = AccountSearchService_XHR.get({
version: "v1",
accountNumber: "1234"
},
function(result) {... etc etc});
The call to my API works fine, everything returns data like I expect - but I'd like to test to see if $scope.accountObj.currentAccount is a Resource before trying to make the .get call (notice the super important capital "R").
When I inspect the object $scope.accountObj.currentAccount in chrome debugger, it looks like:
Resource {accountHolderName: Object, socialSecurityNumer: null, birthDate: "05/14/1965", maritalStatus: ...}
Because of some complexity in my setup though, occasionally it gets overwritten as a normal object (typeof returns "object"), but inspecting it in debugger confirms it lost its Resource status.
So - does anyone know of a way to test whether it is a $resource? Almost like typeof $scope.accountObj.currentAccount returns "Resource"? Or perhaps a better best practices way to ensure that things are connecting up all proper and respectable-like?
All the SO articles I have seen when searching revolve around actual Jasmine testing.
Thanks in advance.
#tengen you need to have injected the type you want to check against, instead of $resource.
All resources are instances of the "class" "Resource", but that's a function that's defined inside of the factory method of the $resource service, so you have no outside visibility to use it with the instanceof operator.
However, you're wrapping that $resource creating with your own custom type, AccountSearchService_XHR, and that's what you need to make the check against.
You need AccountSearchService_XHR to be injected in your code and then perform myRef instanceof AccountSearchService_XHR and that will be === true.
Digging up an old question my intern just had. The simple solution is:
if ($scope.accountObj.currentAccount instanceof AccountSearchService_XHR)
return 'This is a AccountSearchService_XHR Resource';
else
return 'This is not a AccountSearchService_XHR Resource';
which with proper names (Users being a $resource) and real case scenario should lead you to write something like this:
if (!(this.user instanceof Users))
this.user = new Users(this.user);
this.user.$update();
Check it via instanceof yourVariable === "Resource". Because Resource is an object the type will always return as an Object, but if you check that it's an instance of the Resource "class" that should work just fine.

Resources