不能简单地使用ES6承诺更新ng-repeat中的数据?

时间:2015-06-14 22:52:24

标签: javascript angularjs promise ecmascript-6 angular-promise

我正在尝试使用angular和es6 promise构建一个下钻列表。不使用promise我的代码就像在下面的代码片段中演示一样。每次单击父项时,它都会扩展子项(为简单起见,只是样本中的foo和bar)。



angular.module('demo', [])
  .controller('DemoController', ['$scope', 'dataService', function($scope, dataSvc) {
    $scope.entities = dataSvc.loadInitialData();
  }])
  .directive('drillDown', ['$compile', 'dataService', function($compile, dataSvc) {
    return {
      restrict: 'A',
      scope: {
        entities: '='
      },
      controller: function($scope) {
        $scope.load = function() {
          this.entity.subEntities = dataSvc.load();
        };
      },
      compile: function(element) {
        var contents = element.contents().remove();
        var compiled = null;

        return function(scope, element) {
          if (!compiled) {
            compiled = $compile(contents);
          }

          compiled(scope, function(clone) {
            element.append(clone);
          });
        };
      },
      template:
        '<li ng-repeat="entity in entities">' +
          '<a href="#" ng-click="load()"><span ng-bind="entity.name"></span></a>' +
          '<ul drill-down entities="entity.subEntities"></ul>' +
        '</li>'
    };
  }])
  .service('dataService', function() {
    this.loadInitialData = function() {
      return [
        {
          name: 'foo',
          subEntities: []
        },
        {
          name: 'bar',
          subEntities: []
        }
      ];
    };
    this.load = function() {
      return this.loadInitialData();
    };
  });
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.0/angular.min.js"></script>
<div ng-app="demo" ng-controller="DemoController">
  <ul drill-down entities="entities"></ul>
</div>
&#13;
&#13;
&#13;

然而,当我将其更改为使用promise时,出现问题:现在您必须双击该元素以展开它,并且范围也会混乱。

差别主要在于服务和指令控制器中的load函数。到目前为止,我还没有真正研究过角色的$q api,但为什么我只能使用诺言呢? $q中有什么神奇的东西吗?

&#13;
&#13;
angular.module('demo', [])
  .controller('DemoController', ['$scope', 'dataService', function($scope, dataSvc) {
    $scope.entities = dataSvc.loadInitialData();
  }])
  .directive('drillDown', ['$compile', 'dataService', function($compile, dataSvc) {
    return {
      restrict: 'A',
      scope: {
        entities: '='
      },
      controller: function($scope) {
        $scope.load = function() {
          var s = this;
          dataSvc.load().then(function(res) {
            s.entity.subEntities = res;
          });
        };
      },
      compile: function(element) {
        var contents = element.contents().remove();
        var compiled = null;

        return function(scope, element) {
          if (!compiled) {
            compiled = $compile(contents);
          }

          compiled(scope, function(clone) {
            element.append(clone);
          });
        };
      },
      template:
        '<li ng-repeat="entity in entities">' +
          '<a href="#" ng-click="load()"><span ng-bind="entity.name"></span></a>' +
          '<ul drill-down entities="entity.subEntities"></ul>' +
        '</li>'
    };
  }])
  .service('dataService', function() {
    this.loadInitialData = function() {
      return [
          {
            name: 'foo',
            subEntities: []
          },
          {
            name: 'bar',
            subEntities: []
          }
        ];
    };
    this.load = function() {
      return new Promise(function(resolve, reject) {
        resolve([
          {
            name: 'foo',
            subEntities: []
          },
          {
            name: 'bar',
            subEntities: []
          }
        ]);
      });
    };
  });
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.0/angular.min.js"></script>
<div ng-app="demo" ng-controller="DemoController">
  <ul drill-down entities="entities"></ul>
</div>
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:2)

这将要求ES6承诺公开用于设置调度程序的挂钩(如蓝鸟承诺)或公开&#34; post-then&#34;钩子 - 它们都不是公开的。

您必须通过以下方式强制执行ES6对$q的承诺:

$q.when(dataSvc.load()).then(...

或者,您可以编写一个帮助程序将其绑定到范围:

var withDigest = function(fn){
    fn().then(function(){
        $rootScope.evalAsync(angular.noop); // schedule digest if not scheduled
    });
};

然后做:

withDigest(function(){
    return dataSvc.load().then(...
});

答案 1 :(得分:0)

也许是因为你在回调函数

之外的角度世界之外
dataSvc.load().then(function(res) {
  s.entity.subEntities = res;
});

这不是最佳解决方案,但如果您致电$scope.$apply(),它应该有效:

dataSvc.load().then(function(res) {
  s.entity.subEntities = res;
  $scope.$apply()
});

jsfiddle with $ scope。$ apply():)

http://jsfiddle.net/Fieldset/xdxprzgw/

最好的解决方案是使用$ q。

来自angularjs doc:

&#39; $ q与角度中的$ rootScope.Scope Scope模型观察机制集成,这意味着更快地将分辨率或拒绝传播到模型中,避免不必要的浏览器重绘,这将导致UI闪烁。&# 39;&#39;