I am just getting started with angular and saw that you can define a factory to use in multiple controllers.
I have the below code, which is returning my result in the 'success' method fine. But not outside of the function.
I have a feeling its to do with async, but I'm not too sure how to go forward with it, if it is that.
Any help would be appreciated, so thanks in advanced.
var abyssApp = angular.module('abyssApp', []);
abyssApp.factory('abyssData', function($http) {
var result,
products = $http.get('http://abyss.local/products.php');
products.success(function(data) {
result = angular.fromJson(data);
console.log('success: ', result); // object with data in
});
console.log(result); // undefined
});
abyssApp.controller('ItemListCtrl', function($scope, abyssData) {
$scope.items = abyssData;
console.log('abyssData: ', abyssData); // undefined
});
Here's some edits. Note that I'm doing this without really checking, so typeos and mistakes are altogether possible, but the gist of it should make sense.
I made it a service rather than a factory since you really only need a service (singleton) there. A factory would be appropriate if there were different URLs you'd be calling, and wanted to do something like
product = new abyssData('potatoes')
or something.Generally speaking, $http returns a promise object, which itself isn't the data you need, but instead will resolve to the data you need. This promise pattern is repeated a lot in angular (and is getting more and more popular in other javascript venues, because it's awesome (IMO)). That means, on the promise object, you call the .then() method and pass in a function to be called when the promise is resolved. The $http resolves with the result of the XHR. Other promises resolve with other things.
At the end of the promise .then stack, it's good form to put a .catch() call, because exceptions thrown inside a promise generally go into the bitbucket unless you explicitly look for them. It's an in-general flaw to the way promises work, and means you have to be careful for exceptions. With older JS engines, you need to change that to .then()'catch', as catch is kind of a funny word in places. But I'm 90% sure that any JS environment that chokes on .catch won't run angular anyway.
You'll need to expose some of the data or the methods from the factory so that the controller can access it. At the moment there is nothing exposed by the factory.
Depending on your use case, I would suggest something like this:
However, both approaches seem unnecessary to have a factory to encapsulate such a simple query?
Probably three things:
1) Declare the dependency explicit:
for
2) To use the value you want, the factory must return that value so in the end you should be return the "result" variable. Try changing "result" which is a common variable name in xhr requests to prevent overrides.
3) To prevent accessing the data before the return, try to give the method instead of the value:
To use change this:
For this
You have it the other way around. First, the factory should return a value. The value is a singleton. Which means that after the factory is executed, it will not execute itself more than once. What you could do is to return an object which has a reference to your results.
But event this solution doesn't smell very good. Unless your list of objects will never get updated. It would make more sense to return a resource that can be queried when needed. It's not certain that when the controller will get loaded, that the results will be already loaded. Which means that accessing
abyssData.result
might returnundefined
at first and then something else later.But to be honest, what you're trying to do should be done with this:
https://docs.angularjs.org/api/ngResource/service/$resource
You could have a factory like this:
Check this out: https://docs.angularjs.org/api/ngResource/service/$resource
In 'ItemListCtrl' you should inject object created from 'abyssData' factory. Then, it should return $http promise and directly in controller, in success callback, you should assign returned result to $scope.items. It's just one, example way to do this, there's a plenty of methods and patterns on how to resolve such issues in Angular.
logs 'undefined', because when you call this line, there's no response yet. Try to figure out, what promise is and how exactly AJAX calls work, especially what 'success' and 'error' should be defined.