Angularjs error when calling factory method - javascript

I am new to angularjs. I am trying to call a function in a factory but I am getting the below error,
Error: [$injector:undef] Provider 'todoStorage' must return a value from $get factory method.
This is my factory,
todomvc.factory('todoStorage', function ($q,$http) {
var STORAGE_ID = 'todos-angularjs-perf';
function get(){
var promise = $q.defer();
$http.get('http://localhost/test.php').success(function(data){
promise.resolve(data);
});
return promise.promise;
}
});
And this is how I call the function,
var todos = $scope.todos = todoStorage.get();
What exactly is happening and why this error coming up?

todomvc.factory('todoStorage', function ($q,$http) {
var STORAGE_ID = 'todos-angularjs-perf';
function get(){
return $http.get('http://localhost/test.php');
}
return{get:get};
});
//call the service like this
todoStorage.get().then(function(res){
$scope.todos = res.data;
});
Your code is not returning the actual service factory. Since you are using factory you have return some JavaScript object pointing to your internal function. Otherwise it's not a valid factory, and your external code will have no way of getting to the internal get function.

Related

Service variable assigned data but it is always undefined when accessed

I am still new to angular so sorry if my question is a little ...
I created a service that invoke some REST API and I implemented it with promises.
I am currently with this promise return list of data to controller and put it in $scope.
I want that when I receive data in this function also store retrived data to service so I don't have to invoke service again if I already have data.
app.service("MyService", function ($http, $q) {
this.OrignalDataFromService = null;
return {
var deferred = $q.defer();
...
deferred.resolve(data);
this.OrignalDataFromService = data;
return deferred.promise;
}
}
Problem with this is that when I access OrignalDataFromService from controller it is always undefined (in promise I get data it's just service variable that is undefined) why is that?
I don't understand really where should model reside in angular app.
Is it $scope variable in controller and services are just here to allow us to get data from somewhere, or should model be inside service (as a variable)?
OrignalDataFromService is private variable for service, so if you want can access it you need return in object
check this
example:
app.service("MyService", function ($http, $q) {
this.OrignalDataFromService = null;
return {
originalData: this.OrignalDataFromService
}
}
Take a look at the fiddler here. You will have to expose the variable in which you are keeping the original data.
Service
myApp.service('myService', function($q) {
return {
OrignalDataFromService: null,
getData: function() {
var deferred = $q.defer();
var data = ["Data-1", "Data-2", "Data-3"]
deferred.resolve(data);
this.OrignalDataFromService = data;
return deferred.promise;
}
}
});

When calling a function that returns a function that returns a function, how do you get data at the bottom?

How can I access the data from the function inside the function inside the function I'm returning?
projectsRsrc.factory('projectsSrvc', ['$resource', function($resource){
return function(name){
var url = "http://localhost/proj/v3/apiSimulations/projects.json";
var resource = $resource(url);
return resource.get(function(data){
return data;
});
}
}]);
I want to get this data in my controller.
projectsApp.controller('projectsCtrl', ['$scope', 'projectsSrvc', function($scope, projectsSrvc){
$scope.projects = projectsSrvc(name);
}
But projectsSrvc returns a function, and I'm not really sure how to access the function it is returning. Ultimately I want the data to be assigned in my controller
Your factory returns a function and that function returns a promise so in your controller your code should be like this:
projectsSrvc(name).then(function(data) {
$scope.projects = data;
});
Edit: I mixed up $resource with $http so things seem a little different, however everything is explained here: https://docs.angularjs.org/api/ngResource/service/$resource
I got it to work by changing the code to this:
projectsSrvc(name).$promise.then(function(data) {
$scope.projects = data;
});
Tested here: http://jsbin.com/vepivacosa/1/edit?html,js,console
You just need another set of parantheses
$scope.projects = projectsSrvc(name)(argumentmustbepassedhereforthefunction);
But note that you'll need some callback kind of thing(or promises may be?) as you're returning from the ajax call which is asynchronous.
BTW the above code is just a one-liner for
var func = projectsSrvc(name); // store the function reference
$.scope.projects = func(argumentmustbepassedhereforthefunction);

Returning new Object from Service that uses $resource

I am working on making my existing code a bit better and I would like to have two objects for interacting with a RESTful API.
Previously, I used $http to get get the data and return the promise. I would then .then some actions to it. Then I would requery to get additional data and repeat it. So there were several nested $http queries. I would like to avoid that if possible.
I would like to have a service (or a factory) that I can use to configure various query parameters and another object for massaging and outputting the response.
Here is what I have so far:
var solr1 = angular.module('solr', ['ngResource']);
solr1.run(function(){
console.log("Module Loaded");
});
solr1.service('solrser', function($resource,solrresult) {
console.log("In Solrser")
this.serverurl = 'url';
this.res = $resource(this.serverurl);
this.query = function (p) {
this.res.get(p).$promise.then(function(d) {
return solrresult(d);
});
}
});
solr1.factory('solrresult',function() {
return function(a) {
this.data = a;
this.ready = 0;
console.log("In Factory")
this.getdocs = function() {
console.log("Getting Data")
console.log(this.data);
return this.data.docs; //this is line 9
}
return this;
}});
Controller looks like this:
app.controller('app1cont', ['$scope', 'solrser', 'solrresult', function($scope,solrser,solrresult){
console.log("Start");
var res = solrser.query({'q':'potato'});
console.log(res)
console.log(res.getdocs())
}]);
The output looks like this:
Module Loaded solr_module.js:5
In Solrser solr_module.js:9
Start main_controller.js:6
undefined main_controller.js:9
TypeError: Cannot read property 'getdocs' of undefined
at new <anonymous> (.........../main_controller.js:10:21)
at Object.e [as invoke] (https://code.angularjs.org/1.3.1/angular.min.js:36:365)
at F.instance (https://code.angularjs.org/1.3.1/angular.min.js:75:91)
at https://code.angularjs.org/1.3.1/angular.min.js:58:287
at s (https://code.angularjs.org/1.3.1/angular.min.js:7:408)
at G (https://code.angularjs.org/1.3.1/angular.min.js:58:270)
at g (https://code.angularjs.org/1.3.1/angular.min.js:51:172)
at g (https://code.angularjs.org/1.3.1/angular.min.js:51:189)
at https://code.angularjs.org/1.3.1/angular.min.js:50:280
at https://code.angularjs.org/1.3.1/angular.min.js:18:8 angular.js:11339
In Factory solr_module.js:25
So the factory gets created after the controller resumes execution. What am I doing wrong here?
You have a timing issue.
app.controller('app1cont', ['$scope', 'solrser', 'solrresult', function($scope,solrser,solrresult){
console.log("Start");
var res = solrser.query({'q':'potato'});
console.log(res)
console.log(res.getdocs())
}]);
When you call solrser.query() it runs async to get the data. So the res is not populated with any real value until after the promise returns inside the "solrser" service. You would need to do something more like:
solrser.query({'q':'potato'},function(res) {
console.log(res);
console.log(res.getdocs());
}); // could be done as a promise as well....
Separately, you also are doing something really strange when the response is called inside the solrser service.
this.query = function (p) {
this.res.get(p).$promise.then(function(d) {
return solrresult(d);
});
}
Calling return from within the promise handler is not going to do you very much. You need to either call a callback or resolve a deferred. Something like this would work better:
this.query = function (p,callback) {
this.res.get(p).$promise.then(function(d) {
callback(solrresult(d));
});
}
Or as a promise
this.query = function (p) {
var defer = $q.defer();
this.res.get(p).$promise.then(function(d) {
defer.resolve(solrresult(d));
});
return defer.promise;
}
Or you could just pass the get(p).$promise through, etc.
UPDATE:
Since this is an async action, there will always be a promise or callback. You have to do one of:
app.controller('app1cont', ['$scope', 'solrser', 'solrresult', function($scope,solrser,solrresult){
var res = solrser.query({'q':'potato'},function() {
res.getDocs();
});
}]);
Or just straight callback
app.controller('app1cont', ['$scope', 'solrser', 'solrresult', function($scope,solrser,solrresult){
solrser.query({'q':'potato'},function(res) {
res.getDocs();
});
}]);
I see missing semicolon
console.log("In Solrser")
shouldbe
console.log("In Solrser");
also missing semicolon here
console.log("Getting Data")
console.log("In Factory")
in controller you have missing semicolons too.
I think this is a reason why your code don't work.
To avoid bug like missing semicolon you can use JSHint plugin in your IDE

How to return data in a factory method within Angular?

I'm an ionic/Angular n00b and I having trouble wrapping my head around how to do this.
I have a factory defined as such:
angular.module('starter.services', [])
.factory('Calendars', function () {
var calendars;
var success = function(message) {
calendars = message;
return calendars;
};
var error = function(message) {alert("Error: " + message)};
window.plugins.calendar.listCalendars(success,error);
return {
all: function() {
return calendars;
},
get: function(calendarId) {
return calendars[calendarId];
}
}
});
And I'm trying to retrieve the calendars within my controller like this:
.controller('CalendarsCtrl', function($scope,Calendars) {
$scope.calendars = Calendars.all();
})
The factory method is being called but the results are not available until the 'success' callback is invoked so the CalendarsCtrl is always undefined.
How to solve this?
Edit - I've corrected the call within the controller. The same issue remains though, that the function does not return results until the success callback.
You will have to use a promise.
First add the dependency $q
.factory('Calendars', function ($q) {
then in all() you do this
all: function() {
var deferred = $q.defer();
window.plugins.calendar.listCalendars(function(data) {
deferred.resolve(data);
}
,function(error) {
deferred.reject(error); // something went wrong here
});
return deferred.promise;
now this will make the return after the data has been resolved (no more undefined).
One last thing, now when you get the data back at your controller you do this
var promise = Calendars.all();
promise.then(function(data) {
console.log('Success: you can use your calendar data now');
}, function(error) {
console.log('Failed for some reason:' + error);
});
You can read some more about promises here: https://docs.angularjs.org/api/ng/service/$q
I know it's hard to grasp the first time.
Angular factories are returning an object, in order to call their methods you must call them with Calendar.all() which will invoke the inner function.

Angular + requirejs - the controller cannot pick up ajax return data from the factory?

My controller cannot pick up the data that processed from $http.get() in requirejs environment. Any idea how can I fix it?
UserFactory.js
define(['app'], function (app) {
app.module1.factory('UserFactory', ['$http', function($http) {
//your minsafe controller
var factory = {};
factory.getUsers = function(){
$http.get('api.php').success(function(data) {
// here the data from the api is assigned to a variable named users
return data; // [{"id":"1","name":"Big Kev","email":"bigkev#example.com"},{"id":"2","name":"Judy","email":"punk#example.net"},{"id":"3","name":"Suzy","email":"suzy#example.com"},{"id":"4","name":"Joey","email":"sheena#example.org"},{"id":"5","name":"DeeD","email":"deedee#example.net"}]
});
};
return factory;
}]);
});
view.js,
define(['app'], function (app) {
app.module1.controller('View1Ctrl', ['$scope','UserFactory', function($scope,userFactory) {
//your minsafe controller
$scope.message = "Message from View1Ctrl";
$scope.users = userFactory.getUsers();
console.log($scope.users); // undefined
}]);
});
as you can see, I get undefined for $scope.users. It seems that console.log($scope.users); is executed before $http.get('api.php') in the factory. How can I fix this then?
This has nothing to do with Require; it is a very common misconception about how asynchronous code runs (especially promises).
You see factory.getUsers() makes an asynchronous call. The response will be available at a later time and success will be called with the response data at that later time. On the other hand, $scope.users = userFactory.getUsers() is synchronous. It is almost guaranteed that the async call wll NOT have returned by the time the next statement runs. And even if it has returned, the callback will NOT have run because Javascript is single threaded in the browser.
Moreover you have another serious fault: the success callback is "procedural" in the sense that it receives the response and has to do something with it. Its return value is disregarded!
To use promises (or at least $http) correctly in this case, change factory.getUsers to return the $http promise:
factory.getUsers = function(){
return $http.get('api.php');
};
And change the controller to use the promise or the success/error callbacks:
// option (1) with promise
userFactory.getUsers().then(function(response) {
$scope.users = response.data;
});
// option (2) callback
userFactory.getUsers().success(function(data) {
$scope.users = data;
});

Categories

Resources