不能简单地使用 ES6 承诺来更新 ng-repeat 中的数据吗? [英] can't simply use ES6 promise to update data in ng-repeat?

查看:13
本文介绍了不能简单地使用 ES6 承诺来更新 ng-repeat 中的数据吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 angular 和 es6 承诺构建一个向下钻取列表.在不使用 promise 的情况下,我的代码按照下面的代码段中的演示工作.每次单击父级时,它都会展开子级(为简单起见,示例中仅使用 foo 和 bar).

angular.module('demo', []).controller('DemoController', ['$scope', 'dataService', function($scope, dataSvc) {$scope.entities = dataSvc.loadInitialData();}]).directive('drillDown', ['$compile', 'dataService', function($compile, dataSvc) {返回 {限制:'A',范围: {实体:'='},控制器:功能($范围){$scope.load = function() {this.entity.subEntities = dataSvc.load();};},编译:函数(元素){var 内容 = element.contents().remove();var 编译 = null;返回函数(范围,元素){如果(!编译){编译 = $compile(contents);}编译(范围,功能(克隆){element.append(克隆);});};},模板:'<li ng-repeat="实体中的实体">'+'<a href="#" ng-click="load()"><span ng-bind="entity.name"></span></a>'+'<ul 下钻实体="entity.subEntities"></ul>'+'</li>'};}]).service('dataService', function() {this.loadInitialData = function() {返回 [{名称: 'foo',子实体:[]},{name: '酒吧',子实体:[]}];};this.load = function() {返回 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 下钻实体="实体"></ul>

但是,当我将其更改为使用 promise 时,出现了问题:现在您必须双击该元素才能展开它,而且范围也被弄乱了.

区别本质上只是服务中的 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) {返回 {限制:'A',范围: {实体:'='},控制器:功能($范围){$scope.load = function() {var s = 这个;dataSvc.load().then(function(res) {s.entity.subEntities = res;});};},编译:函数(元素){var 内容 = element.contents().remove();var 编译 = null;返回函数(范围,元素){如果(!编译){编译 = $compile(contents);}编译(范围,功能(克隆){element.append(克隆);});};},模板:'<li ng-repeat="实体中的实体">'+'<a href="#" ng-click="load()"><span ng-bind="entity.name"></span></a>'+'<ul 下钻实体="entity.subEntities"></ul>'+'</li>'};}]).service('dataService', function() {this.loadInitialData = function() {返回 [{名称: 'foo',子实体:[]},{name: '酒吧',子实体:[]}];};this.load = function() {返回新的承诺(功能(解决,拒绝){解决([{名称: 'foo',子实体:[]},{name: '酒吧',子实体:[]}]);});};});

<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 下钻实体="实体"></ul>

解决方案

这将要求 ES6 承诺公开一个用于设置调度程序的钩子(如 bluebird 承诺)或公开post-then"钩子——两者都不是公开.

您必须通过执行以下操作将 ES6 承诺强制转换为 $q:

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

或者,您可以编写一个帮助器将其绑定到作用域:

var withDigest = function(fn){fn().then(function(){$rootScope.evalAsync(angular.noop);//如果未安排,则安排摘要});};

然后做:

withDigest(function(){返回 dataSvc.load().then(...});

I'm trying to build a drill-down list with angular and es6 promise. Without using promise my code works as demoed in the snippet below. Every time you click the parent, it expands the children (just foo and bar in the sample for simplicity).

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>

However when I change it to using promise, something goes wrong: now you'd have to double click the element to expand it and the scopes are also messed up.

The difference is essentially just in the load function in the service and the directive controller. So far I haven't really looked into angular's $q api but why can't I just use promise? Is there some magic there in $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>

解决方案

This would require ES6 promises to either expose a hook for setting the scheduler (like bluebird promises) or to expose "post-then" hooks - neither of which it does publicly.

You'd have to coerce the ES6 promise to a $q one by doing:

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

Alternatively, you can write a helper for binding it to a scope:

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

And then do:

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

这篇关于不能简单地使用 ES6 承诺来更新 ng-repeat 中的数据吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆