query() with Angular $resources always “Undefined is not a function” - javascript

I simply use following code to call query() with ngRecourse, but it always hits “Undefined is not a function”
[demo.js]
var app = angular.module('StarterApp', ['ngResource']);
app.factory("resourceFactory", function($resource) {
return $resource("js/demo2.json", {}, {
'get':{method:'GET'},
'query':{method:'GET',isArray:true,url:"js/demo2.json"},
'save':{method:'POST'}
});
});
app.controller('appCtrl', function($scope, resourceFactory){
'use strict';
var ajax = new resourceFactory;
ajax.$query(function(response) {
console.log(response);
});
});
[demo2.json]
[
{"demo2":"test"}
]
[error]
TypeError: undefined is not a function
at http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-resource.min.js:9:466
at s (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:7:302)
at d.module.provider.$get.e.(anonymous function).q.then.p.$resolved (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular-resource.min.js:9:423)
at http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:112:20
at l.$get.l.$eval (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:125:305)
at l.$get.l.$digest (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:122:398)
at l.$get.l.$apply (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:126:58)
at l (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:81:171)
at S (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:85:301)
at XMLHttpRequest.D.onload (http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js:86:315)
If I use "$get" with simple object return, it works. So I am pretty not sure what is going wrong with my code.

It should be simply resourceFactory.query instead of resourceFactory.$query & also there is no need to create a instance of object using new keyword
Code
resourceFactory.query(function(response) {
console.log(response);
});

I think this is because you try do promise on an Array.
I got the same issue and put the WebService array wrapped in a JSON
ie:
{ list: myArray })
instead of:
myArray
and works as a charm!
I use the same version of angularJS, and the undefined is looking for the push methods.
I just found the issue on GitHub Issue 56 and it's still open!

Related

AngularJS: get promise value without internal properties

Ok, another promise-related question (I see there are already quite a few of them). I'm trying to get promise result from endpoint and use it in ng-repeat, first is the typical response from endpoint:
{"ebbe5704-4ea5-470e-8ab9-102ee8ca457f":"Foo",
"e380a6f7-2f88-46bb-bd54-251719353627":"Bar"
}
here's how I get it from promise:
RequestService.getValues().$promise.then(function(res) {
vm.result = res;
});
and here I render it in HTML:
<p ng-repeat="i in vm.result">{{i}}</p>
The problem is the rendered view contains internal fields of the promise ($promise and $resolved):
Am I doing something wrong? Is there any less ugly way instead of filtering through result keys?
UPD:
RequestService.getValues is a $resource, so can be replaced like this:
$resource("/rest/", null, {
getValues: {
url: "/rest/values/",
method: "GET"
}
}).getValues().$promise.then(function(res) {
vm.result = res;
console.log("RES:", res);
});
The problem here is that you are iterating with ng-repeat over an object (so getting the keys of each property of the object) and not over an array.
AngularJS resources are made to be used with ng-repeat only if the returned resource is an array.
When facing an object ng-repeat uses something like for(var key in obj) whereas when facing an array it uses the indexer to loop as following for(var i=0; i<arr.length; i++). Thus, with an array, it is skipping other properties like $promise and so.
What you should do is implement a custom filter that will skip angular decorators methods away from the ng-repeat iteration:
$scope.skipResourceFn= function(key)
{
// is it an angular decorator (starting with '$' char):
return key.indexOf('$') != 0;
};
Then in your template:
<p ng-repeat="i in vm.result | filter:skipResourceFn">{{i}}</p>
One can use the $http service to get the object:
var config = {
url: "/rest/values/",
method: "GET"
};
$http(config).then(function(response) {
var data = response.data;
vm.result = data;
console.log("RES:", data);
});
The $http service does not append additional properties to an object.

AngularJS - Error: [ng:areq] Argument 'fn' is not a function, got string

I get an error:
Error: [ng:areq] Argument 'fn' is not a function, got string
I read and apply the others recommendation. But I have not solved the problem.
Here is my code:
controller.js
angular.module('starter.controllers', [])
.controller('DashCtrl', function ($scope,$ionicScrollDelegate,SocketService) {
var me = this;
me.messages = [];
$scope.sendTextMessage = function() {
var msg = {
'text': me.messages
}
me.messages.push(msg);
$ionicScrollDelegate.scrollBottom();
me.messages = '';
SocketService.emit('mesaj', msg);
};
});
services.js
angular.module('starter.services', [])
.service('SocketService', ['socketFactory'],
function SocketService(socketFactory) {
return socketFactory({
ioSocket: io.connect('http://l92.168.1.27:3000')
});
});
Remove second parameter when declaring angular module.
So change this : angular.module('starter.controllers', [])
To this: angular.module('starter.controllers')
Two things that jump out at me;
1) no injections; fix these lines to:
.controller('DashCtrl', ['scope', '$ionicScollDelegate', 'SocketService', function ($scope,$ionicScrollDelegate,SocketService){
and
.service('SocketService', ['socketFactory',
Although that last line, I would simply write the SocketService() function into it like so:
app
.service('SocketService', ['socketFactory', function(socketFactory) {
return socketFactory({
ioSocket: io.connect('http://l92.168.1.27:3000')
});
}])
2) You appear to have two apps. Instead of throwing angular.module() all over, define it in one place:
var app = angular.module('starter', []);
Then you can use it elsewhere like so:
app
.service('SocketService, [.... etc
See that in action in the second part of 1)

TypeError: Cannot read property 'unshift' of undefined AngularJS

I'm working on this new AngularJS project with ngStorage (localStorage) and not quite sure why I'm getting the message below. I get this whenever I click on my add button.
TypeError: Cannot read property 'unshift' of undefined AngularJS
Below is my code. Can someone explain why this error is occurring?
.factory ('StorageService', function($localStorage) {
$localStorage = $localStorage.$default({
favorites: []
});
var _getAll = function () {
return $localStorage.favorites;
};
var _add = function (color) {
$localStorage.favorites.unshift(color);
}
var _remove = function (color) {
$localStorage.favorites.splice(index, 1);
}
return {
getAll: _getAll,
add: _add,
remove: _remove
};
})
controller
.controller('HomeCtrl', function($scope, $localStorage, dataService, StorageService) {
$scope.add = function (color) {
StorageService.add(StorageService.favorites.unshift(dataService.colors.indexOf(color)));
console.log(color);
};
)};
What exactly are you trying to accomplish with the line in your controller:
StorageService.add(StorageService.favorites.unshift(dataService.colors.indexOf(color)));
I assume you want to call the add method of your service and pass it the value of color in dataService.
As metioned in the other answers your error comes from favorites not being defined in the return block of your service. But if you do define it you still won't be adding the color since unshift will return the new length of StorageService.favorites.
If my asumption is correct you'll probably want to do something like:
StorageService.add(dataService.colors.indexOf(color));
If you do need to "get" the favorites from your service, don't break your encapsulation by publishing $localStorage.favorites but use your getAll method to get the "favorites".
P.S. Also don't forget to check that dataService actually has a colors key or you have another potential null-pointer.
You can access the favorites array like this (use the getAll function that is already exposed):
StorageService.add(StorageService.getAll.unshift(dataService.colors.indexOf(color)));

Call angularjs service from simple js code

I have the following angularjs service:
angular.module('app.main').factory('MyService', ["$http", function ($http) {
return new function () {
this.GetName = function () {
return "MyName";
};
};
}]);
How can I call GetName function from MyService from legacy js code?
Use angular.injector. Using your code you can do something like the following:
angular.module('main.app', []).factory('MyService', ['$http', function ($http) {
return new function () {
this.GetName = function () {
return "MyName";
};
};
}]);
angular.injector(['ng', 'main.app']).get("MyService").GetName();
Here is the jsfiddle: http://jsfiddle.net/wGeNG/
NOTE - You need to add "ng" as your first module before loading your custom module since your example code depends upon $http provider which is in the ng module.
EDIT - Using get() as in OP's answer but note this code is fetching the service without relying upon the element being bound to the app module "main.app".
For me it worked with:
angular.element(document.body).injector().get("MyService")
I got 'Unknown provider' error when tried this:
angular.injector(['ng', 'main.app']).get("MyService")
and as i am using jqLite, i can't do
angular.element('*[ng-app]')
because selectors are not supported by jqLite, but i got [Dor Cohen] idea. My directive ng-app is on my body tag, then i can use:
angular.element(document.body).injector().get("MyService")
or
angular.element(document).find('body').injector().get("MyService")
Using the following line helps to execute my method from the angularjs service:
angular.element('*[ng-app]').injector().get("MyService").GetName ();
Here's a utility method that I use :
function getService(name, element) {
element = element || '*[ng-app]';
return angular.element(element).injector().get(name);
}
getSrv("name-of_service", document.body)

Why is my controller property 'undefined' when I assign it the result of $resource query()?

I have a JSON data structure:
[
{
"title" :"a1",
"id" :"b1",
"name" :"c1"
},
{
"title" :"a2",
"id" :"b2",
"name" :"c2"
}
]
I am accessing is as an external JSON and parsed through a factory method. I want it to assign it to a Javascript variable in my controller.
function Control($scope,data)
{
var e=data.query(); /* getting the external JSON data */
alert(e[0].title);
}
It says that e[0] is undefined. Is there any other way I can assign it to a Javascript variable and then traverse through it? Please help.
Most likely, #Marty is correct. If you are using the query() method from the $resource service, it is asynchronous. This will likely do what you want:
data.query( function( data ) {
var e = data;
alert(e[0].title);
});
Okay, so $resource can be confusing like this... It immediately gives you a reference to the return object, but doesn't update the object until the asynchronous AJAX call returns... so...
If you put your return value from data.query() in a property on $scope, since it's $watched when you bind it in your view, you'll see it update. HOWEVER, if you're just trying to alert it, it will alert the value before it's been updated.. again because of the async aspect of $resource.
Otherwise, you can get the value the way that #MarkRajcok has shown in his answer.
Here is a psuedo-code illustration of ways you can use $resource query();
app.controller('FooCtrl', function($scope, $resource) {
var Bar = $resource('/Bar/:id', {id: '#id'});
// here, we get the result reference and stick it in the scope,
// relying on a digest to update the value on our screen.
$scope.data = Bar.query();
//OR
//here we already have a reference.
var test = Bar.query(function() {
//in here, test has been populated.
$scope.data2 = test;
});
alert(test); //not populated here, yet.
//OR
Bar.query(function(x) {
$scope.data3 = x;
});
});
This is all done so the object(s) returned can have functions pre-instantiated on them like $save(), etc.

Categories