javascript - 不能简单地使用 ES6 Promise 来更新 ng-repeat 中的数据吗?

标签 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();
    };
  });
<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>

但是,当我将其更改为使用 Promise 时,出现了问题:现在您必须双击该元素才能展开它,并且范围也变得困惑。

本质上的区别仅在于服务和指令 Controller 中的 load 函数。到目前为止,我还没有真正研究过 Angular 的 $q api,但为什么我不能只使用 Promise 呢? $q 有什么魔力吗?

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: []
          }
        ]);
      });
    };
  });
<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>

最佳答案

这将要求 ES6 Promise 要么公开一个用于设置调度程序的钩子(Hook)(如 Bluebird Promise),要么公开“Post-then”钩子(Hook)——这两者都不是公开的。

您必须通过执行以下操作将 ES6 promise 强制为 $q :

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

或者,您可以编写一个帮助器将其绑定(bind)到范围:

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

然后执行:

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

关于javascript - 不能简单地使用 ES6 Promise 来更新 ng-repeat 中的数据吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30835399/

相关文章:

javascript - 使用 Node.js 库从平衡支付中获取 JSON 数据

javascript - 这段代码中的 Promise 是如何工作的?

javascript - Slack 和 Hipchat 使用什么技术栈?

javascript - 我需要帮助在页面加载时创建一个在父窗口关闭时关闭的 javascript 弹出窗口

javascript - $_SESSION 破坏 url 中的参数(在 Angular 项目中)

javascript - Angular $watch 在 init 时触发?

javascript - 在不使用return或嵌套if的情况下以reject结束promise函数,这怎么可能?

javascript - 制作一个返回各种数组的函数?

javascript - Crossrider 扩展平台

css - 在 li 元素前面追加一个元素