Reputation: 167
I am trying to create a factory for angular module which returns a JSON object received through angular's $http.get()
.
Within the callback function for success()
, I am trying to assign the object to the variable products
. It seems products
is getting returned from the factory function before the assignment could take place.
Can someone advise how the below code can be synchronized? How do we delay execution of return products;
until $http.get('/products').success();
is complete?
Also is there a better approach?
angular.module('app', ['ngRoute'])
.factory('products', ['$http',function ($http) {
var products;
$http.get('/products').success(function(data,status,header,config){
products=data;
console.log(products); //[Object, Object, Object]
});
console.log(products); //undefined
return products;
}])
UPDATE
angular.module('app', [])
.factory('members1', ['$http',
function ($http) {
var members1=[];
$http({
method: 'GET',
url: '/members.json'
}).success(function (data, status, headers, cfg) {
members1=data;
});
return members1;
}])
.factory('members2', ['$http',
function ($http) {
var members2=[];
$http({
method: 'GET',
url: '/members.json'
}).success(function (data, status, headers, cfg) {
angular.copy(data,members2);
});
return members2;
}])
.controller('controller1', ['$scope','members1','members2',
function ($scope,members1,members2) {
$scope.members1=members1;
$scope.members2=members2;
}]);
above code has two identical factories with just one difference (angular.copy instead of assignment). The one with angular.copy works for the below template.
<div ng-controller="controller1">
<div>
Using Members1 Factory
<ul>
<li ng-repeat="member in members1">{{member.name}}</li>
</ul>
</div>
<div>
Using Members2 Factory
<ul>
<li ng-repeat="member in members2">{{member.name}}</li>
</ul>
</div>
</div>
view :
Using Members1 Factory
Using Members2 Factory
Name1
Name2
Name3
Upvotes: 1
Views: 298
Reputation: 52837
I prefer the approach of returning the data from the service (which would be initially empty) and populate it once the $http promise is resolved, all-the-while preserving the array reference:
angular.module('app', ['ngRoute'])
.factory('products', ['$http',function ($http) {
var products = [];
$http.get('/products').success(function(data,status,header,config){
angular.copy(data, products);
console.log(products); //[Object, Object, Object]
});
console.log(products); // empty initially, populated when promise resolved.
return products;
}])
Upvotes: 1
Reputation: 2585
I belived, you want to encapsulate your data logic inside services. Here is a cleaner approach.
var app=angular.module('app',['ngRoute']);
app.factory('products', ['$http',function ($http,$q) {
return{
getAll:function(){
var deffered = $q.defer();
$http.get('/products').success(function(data,status,header,config){
deffered.resolve(data);
}).error(function(status){
deffered.reject(status);
});
return deffered.promise;
}
};
}]);
app.controller('myController',function myController($scope, products){
products.getAll().then(function(data){
//the property that needs to bind on view
$scope.products=data;
});
});
Upvotes: 1
Reputation: 19123
The good news is that you are very close. The $http.get
method is designed to do just what you want and so its return value is a promise
(if that doesn't mean much to you then you need to go learn about the angular $q library)
So you don't try and return the products themselves, instead you just return the promise and use it
Upvotes: 0
Reputation: 1204
The best way to go with this problem in my opinion is to use the promise that $http returns by default.
angular.module('app', ['ngRoute'])
.factory('products', ['$http',function ($http) {
return $http.get('/products');
}]);
Then in your controller/directive/anywhere where you want to inject your factory you could use something like:
angular.module('app').controller('ExampleCtrl', function ($scope, products) {
products.then(function (data) {
$scope.products = data;
});
});
Upvotes: 1