我有以下服务:
app.service('Library', ['$http', function($http) {
this.fonts = [];
this.families = [];
// ... some common CRUD functions here ...
// Returns the font list
this.getFonts = function() {
if(_.isEmpty(this.fonts)) this.updateFonts();
return this.fonts;
};
// Returns the family list
this.getFamilies = function() {
if(_.isEmpty(this.families)) this.updateFamilies();
return this.families;
};
// Update the font list
this.updateFonts = function() {
var self = this;
$http.get(BACKEND_URL+'/fonts').success(function(data) {
self.fonts = data;
console.log('Library:: fonts updated', self.fonts);
});
};
// Update the family
this.updateFamilies = function() {
var self = this;
$http.get(BACKEND_URL+'/families').success(function(data) {
var sorted = _.sortBy(data, function(item) { return item });
self.families = sorted;
console.log('Library:: families updated', self.families);
});
};
}]);
以下主控制器代码:
app.controller('MainController', ['$scope', '$state', 'Cart', 'Library', function($scope, $state, Cart, Library) {
console.log('-> MainController');
// Serve the right font list depending on the page
$scope.fonts = $state.is('home.cart') ? Cart.getFonts() : Library.getFonts();
$scope.families = Library.getFamilies();
}]);
问题是,当视图请求$scope.fonts
的内容时,它仍然是空的。
加载结束后如何更新$scope.fonts
和$scope.families
我可以使用$scope.$watch
,但我确信有更简洁的方法可以做到这一点......
答案 0 :(得分:2)
这就是promises的真正含义。您的服务应返回要解决的承诺。您还可以简化服务:
app.service('Library', ['$http', '$q', function($http, $q) {
var self = this;
self.families = [];
// Returns the family list
self.getFamilies = function() {
var deferred = $q.defer();
if(_.isEmpty(self.families)) {
$http.get(BACKEND_URL+'/families').success(function(data) {
var sorted = _.sortBy(data, function(item) { return item });
self.families = sorted;
deferred.resolve(self.families);
console.log('Library:: families updated', self.families);
});
} else {
deferred.resolve(self.families);
}
return deferred.promise;
};
}]);
然后在您的控制器中,使用promises then
方法:
app.controller('MainController', ['$scope', '$state', 'Cart', 'Library', function($scope, $state, Cart, Library) {
console.log('-> MainController');
// Serve the right font list depending on the page
$scope.fonts = $state.is('home.cart') ? Cart.getFonts() : Library.getFonts();
Library.getFamilies().then(function(result) {
$scope.families = result;
});
}]);
由于$ http,这是未经测试的,但这是使用$ timeout的演示:
答案 1 :(得分:1)
考虑传递一个回调函数。
服务:
this.getFonts = function(callback) {
if(_.isEmpty(this.fonts)) this.updateFonts(callback);
return this.fonts;
};
this.updateFonts = function(callback) {
var self = this;
$http.get(BACKEND_URL+'/fonts').success(function(data) {
self.fonts = data;
console.log('Library:: fonts updated', self.fonts);
callback(data);
});
};
控制器:
Library.getFonts(function (data) { $scope.fonts = data; });
这可以稍微整理一下,因为回调消除了对某些代码的需要,但它将作为一个例子。
答案 2 :(得分:1)
感谢所有答案!我最终使用了回调和承诺的混合,如下所示:
app.service('Library', function($http) {
// Returns the font list
this.getFonts = function(callback) {
if(_.isEmpty(self.fonts)) return self.updateFonts(callback);
else return callback(self.fonts);
};
// Update the font list
this.updateFonts = function(callback) {
return $http.get(BACKEND_URL+'/fonts').success(function(data) {
self.fonts = data;
callback(data);
});
};
});
而且,在控制器中:
app.controller('MainController', function(Library) {
Library.getFonts(function(fonts) { $scope.fonts = fonts });
});
我尝试了你的所有建议,但这是我用其余代码处理的最佳建议。
答案 3 :(得分:0)
在this.getFonts
函数(以及其他函数)中,从this
调用数据,该数据指向函数而不是所需的控制器范围。请尝试以下方法:
var self = this;
self.fonts = [];
self.families = [];
// ... some common CRUD functions here ...
// Returns the font list
self.getFonts = function() {
if(_.isEmpty(self.fonts)) self.updateFonts();
return self.fonts; // <-- self.fonts will point to the fonts you want
};
答案 4 :(得分:0)
我会尝试在
中包装你正在调用的getScope和getFonts体$scope.$apply(function(){ ...body here... });
答案 5 :(得分:0)
确保在任何功能之外声明var self = this;
self.data = [];
this.updateFonts = function() {
self.fonts = $http.get(BACKEND_URL+'/fonts').success(function(data) {
return data.data
});
return self.fonts
};
。
将调用分配给要存储数据的值,然后将其返回。
beforeEach(module('myServiceApp'));
beforeEach(inject(function(_CommonService_) {
CommoService = _CommonService_;
}));
答案 6 :(得分:0)
因为您正在使用ui-router(我看到了$ state)。您可以在州内使用解决方案并返回承诺。
Doc:https://github.com/angular-ui/ui-router/wiki
例如:
$stateProvider.state('myState', {
resolve:{
// Example using function with returned promise.
// This is the typical use case of resolve.
// You need to inject any services that you are
// using, e.g. $http in this example
promiseObj: function($http){
// $http returns a promise for the url data
return $http({method: 'GET', url: '/someUrl'});
}
},
controller: function($scope,promiseObj){
// You can be sure that promiseObj is ready to use!
$scope.items = promiseObj.data;
}
}
在您的情况下,您需要将this.getFonts和getFamilies转换为承诺
this.getFonts = function(){
return $http.get(BACKEND_URL+'/fonts').success(function(data) {
self.fonts = data;
console.log('Library:: fonts updated', self.fonts);
});
}
有很多方法可以做到这一点,但在我看来,解决方法是最好的。