从服务器加载数据后设置所选项目

时间:2014-11-09 23:06:50

标签: angularjs angularjs-service angularjs-controller

在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

http://plnkr.co/edit/ltRF2KSnz0zXtFxXU5hE?p=preview

1 个答案:

答案 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。

如果数据以某种方式更改 在此控制器之外,那么我会开始将事件视为保持控制器同步的一种方式。