不能简单地使用 ES6 promise 在 ng-repeat 中更新数据吗?
can't simply use ES6 promise to update data in ng-repeat?
我正在尝试使用 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 时,出现了问题:现在您必须双击该元素才能将其展开,并且范围也被弄乱了。
主要区别在于服务和指令控制器中的 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>
可能是因为你在回调函数的angular世界之外
dataSvc.load().then(function(res) {
s.entity.subEntities = res;
});
这不是最好的解决方案,但如果您调用 $scope.$apply()
它应该有效:
dataSvc.load().then(function(res) {
s.entity.subEntities = res;
$scope.$apply()
});
jsfiddle 与 $scope.$apply() :)
http://jsfiddle.net/Fieldset/xdxprzgw/
最好的解决方案是使用 $q。
来自 angularjs 文档:
'$q 与 angular 中的 $rootScope.Scope Scope 模型观察机制集成,这意味着可以更快地将分辨率或拒绝传播到您的模型中,并避免不必要的浏览器重绘,这会导致闪烁 UI.''
这将要求 ES6 承诺公开一个用于设置调度程序的钩子(如 bluebird 承诺)或公开 "post-then" 钩子——这两者都不是公开的。
您必须通过以下方式将 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(...
});
我正在尝试使用 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 时,出现了问题:现在您必须双击该元素才能将其展开,并且范围也被弄乱了。
主要区别在于服务和指令控制器中的 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>
可能是因为你在回调函数的angular世界之外
dataSvc.load().then(function(res) {
s.entity.subEntities = res;
});
这不是最好的解决方案,但如果您调用 $scope.$apply()
它应该有效:
dataSvc.load().then(function(res) {
s.entity.subEntities = res;
$scope.$apply()
});
jsfiddle 与 $scope.$apply() :)
http://jsfiddle.net/Fieldset/xdxprzgw/
最好的解决方案是使用 $q。
来自 angularjs 文档:
'$q 与 angular 中的 $rootScope.Scope Scope 模型观察机制集成,这意味着可以更快地将分辨率或拒绝传播到您的模型中,并避免不必要的浏览器重绘,这会导致闪烁 UI.''
这将要求 ES6 承诺公开一个用于设置调度程序的钩子(如 bluebird 承诺)或公开 "post-then" 钩子——这两者都不是公开的。
您必须通过以下方式将 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(...
});