在AngularJS中,加载初始数据和设置所选选项的最佳做法是什么?例如,假设我有两个服务,如下所示
加载初始配置的服务
app.service('ConfigService', function($timeout){
var self = this;
self.config = {};
// simulate loading configuration from server
self.loadConfig = function(){
$timeout(function(){
self.config = {preferredId:2};
}, 2000);
};
self.loadConfig();
});
加载初始数据的服务
app.service('DataService', function($timeout){
var self = this;
self.data = [];
// simulate fetching data from server
self.loadData = function(){
$timeout(function(){
self.data = [{id:1, name: 'apple'}, {id:2, name:'mango'}, {id:3, name:'papaya'}];
}, 3000);
};
self.loadData();
});
在我的控制器中,我想使用来自服务2的数据显示选项列表,并使用服务1中的配置设置当前选择的选项。我目前使用$ scope。$ watch来设置所选选项,如下所示
app.controller('MainCtrl', function($scope, DataService, ConfigService) {
$scope.selectedItem = null;
$scope.DataService = DataService;
$scope.ConfigService = ConfigService;
// set selected item
$scope.setSelectedItem = function(){
if(ConfigService.config && ConfigService.config.preferredId){
$scope.selectedItem = _.find(DataService.data, function(item){
return item.id == ConfigService.config.preferredId;
});
}
};
// use watchers to update the selected value if the service loads after the controller
$scope.$watchCollection('DataService', function() {
$scope.setSelectedItem();
});
$scope.$watchCollection('ConfigService', function() {
$scope.setSelectedItem();
});
});
是否使用$ scope。$ watch为此目的被视为不良做法?我也可以修改我的代码来监听事件并执行如下所示的相同操作(为简洁省略服务代码)
app.controller('MainCtrl', function($scope, DataService, ConfigService, $rootScope) {
$scope.selectedItem = null;
$scope.DataService = DataService;
$scope.ConfigService = ConfigService;
// set selected item
$scope.setSelectedItem = function(){
if(ConfigService.config && ConfigService.config.preferredId){
$scope.selectedItem = _.find(DataService.data, function(item){
return item.id == ConfigService.config.preferredId;
});
}
};
$rootScope.$on('DataService:loaded',function(){
$scope.setSelectedItem();
});
$rootScope.$on('ConfigService:loaded',function(){
$scope.setSelectedItem();
});
});
这被认为是设置我选择的选项的正确或首选方式还是我错过了另一种更好的方法?
使用$ scope插入。$ watch
http://plnkr.co/edit/9Lb6cmirR2J8AiuYiuwU?p=preview
使用$ rootScope进行插入。$ broadcast和$ rootScope。$ on
答案 0 :(得分:0)
我希望这会有所帮助,因为我有点改变了你的榜样。 :)
首先,您使用$timeout
对服务器进行的模拟通常不是您所看到的。 service
通常充当数据的渠道,但状态不一定会像self
一样保持在您的位置。这样做需要$watch
数据才能采取行动(比如绑定到范围)。
在my fork of your plunker中,我使用$timeout
作为设置承诺的方式,而不是仅使用$q
。这是更典型的实际$http
服务在Angular中的工作方式。所以,现在这是服务代码:
// service that controls user configuration
app.service('ConfigService', function($timeout, $q){
var self = this;
// simulate loading configuration from server
self.loadConfig = function(){
var deferred = $q.defer();
$timeout(function(){
deferred.resolve({preferredId:2});
}, 2000);
return deferred.promise;
};
});
// service that controls data
app.service('DataService', function($timeout, $q){
var self = this;
// simulate fetching data from server
self.loadData = function(){
var deferred = $q.defer();
$timeout(function(){
deferred.resolve([{id:1, name: 'apple'}, {id:2, name:'mango'}, {id:3, name:'papaya'}]);
}, 3000);
return deferred.promise;
};
});
数据保持不变。但是,我们现在承诺直接在控制器中处理:
app.controller('MainCtrl', function($scope, DataService, ConfigService) {
$scope.selectedItem = null;
$scope.selectedOption = {};
ConfigService.loadConfig().then(function(data) {
$scope.selectedOption = { id: data.preferredId };
});
DataService.loadData().then(function(options) {
$scope.possibleOptions = options;
});
});
在这里,我处理从promise解析回来的数据并绑定到范围。就这些。你会注意到另外一件事。我将preferredId
打包并使用id
属性对象:
$scope.selectedOption = { id: data.preferredId };
这允许我使用track by
中的ng-options
语法自动设置所选项目(documentation with select):
<body ng-controller="MainCtrl">
<select ng-model="selectedOption" ng-options="item.name for item in possibleOptions track by item.id"></select>
</body>
这是你处理这类事情的典型方式,IMO。
如果数据以某种方式更改 在此控制器之外,那么我会开始将事件视为保持控制器同步的一种方式。