Angular JS:如何绑定到承诺 [英] Angular JS: how to bind to promises
问题描述
我正在尝试将承诺绑定到视图.我不知道你是否可以直接做到这一点,但这就是我正在尝试做的.知道我做错了什么吗?
注意:源代码有点人为设置超时并使用静态数据,但这是为了使代码更易于诊断.
JSFiddle 页面:http://jsfiddle.net/YQwaf/27/
解决方案:事实证明您可以直接绑定承诺.我的原始代码有两个问题:
- 使用 setTimeout() 而不是 angular 的 $timeout 是一个问题.Angular 不知道它需要在超时触发时刷新 UI(您可以使用 $scope.$apply 在 setTimeout 中解决这个问题,或者您可以只使用 $timeout )
- 绑定到返回承诺的函数是一个问题.如果它第二次被调用,它会做出另一个承诺.更好的是为承诺设置一个范围变量,并仅根据需要创建一个新的承诺.(就我而言,这是在国家/地区代码上调用 $scope.$watch)
HTML:
区域代码 国家代码<select ng:model="countryCode"><option value="US">美国</option><option value="CA">加拿大</option></select>
JS:
function addressValidationController($scope, $q) {变量区域 = {美国:[{code: 'WI',name: 'Wisconsin'}, {code: 'MN',name: 'Minnesota'}],CA:[{代码:'ON',名称:'安大略'}]};$scope.getRegions = 函数 () {var deferred = $q.defer();设置超时(函数(){var countryRegions = region[$scope.countryCode];控制台日志(国家/地区);如果(国家/地区 === 未定义){deferred.resolve([]);} 别的 {deferred.resolve(countryRegions);}}, 1000);返回 deferred.promise;};}
警告:这个答案在编写时是准确的,但是从 1.2 开始,Angular 模板引擎不会透明地处理承诺!-- @Malvolio
是的,模板引擎(和表达式)透明地处理承诺,但我会将承诺分配给控制器中的范围属性,而不是每次返回新承诺的函数时都调用(我认为这是您的问题,已解决的承诺丢失因为每次都会返回一个新的承诺).
JSFiddle:http://jsfiddle.net/YQwaf/36/
HTML:
区域代码 国家代码<select ng:model="countryCode"><option value="US">美国</option><option value="CA">加拿大</option></select>
JS:
function addressValidationController($scope, $q, $timeout) {变量区域 = {我们: [{代码:'WI',name: '威斯康星州'},{代码:'MN',名称:'明尼苏达'}],CA:[{代码:'开',名称:'安大略'}]};函数 getRegions(countryCode) {console.log('getRegions:' + countryCode);var deferred = $q.defer();$超时(功能(){var countryRegions = region[countryCode];如果(国家/地区 === 未定义){console.log('解决空');deferred.resolve([]);} 别的 {console.log('解决');deferred.resolve(countryRegions);}}, 1000);返回 deferred.promise;};$scope.regions = [];//管理国家变更:$scope.$watch('countryCode', function(countryCode) {如果(angular.isDefined(国家代码)){$scope.regions = getRegions(countryCode);}别的 {$scope.regions = [];}});}
I am trying to bind a promise to a view. I don't know if you can do that directly, but that's what I'm attempting to do. Any ideas what I am doing wrong?
Note: the source is a little contrived with the timeout and uses static data, but that's to make the code easier to diagnose.
EDIT: JSFiddle Page: http://jsfiddle.net/YQwaf/27/
EDIT: SOLUTION: It turned out you can directly bind promises. I had two problems with my original code:
- Using setTimeout() instead of angular's $timeout was a problem. Angular doesn't know it needs to refresh the UI when the timeout is triggered ( You could solve this with $scope.$apply inside setTimeout, or you can just use $timeout )
- Binding to a function that returned a promise was a problem. If it gets called a second time, it makes yet another promise. Better is to set a scope variable to the promise and only create a new promise as needed. (In my case, this was calling $scope.$watch on the Country Code)
HTML:
<div ng:controller="addressValidationController">
Region Code <select ng:model="regionCode" ng:options="r.code as r.name for r in getRegions()"/>
Country Code<select ng:model="countryCode"><option value="US">United States</option><option value="CA">Canada</option></select>
</div>
JS:
function addressValidationController($scope, $q) {
var regions = {
US: [{code: 'WI',name: 'Wisconsin'}, {code: 'MN',name: 'Minnesota'}],
CA: [{code: 'ON',name: 'Ontario'}]
};
$scope.getRegions = function () {
var deferred = $q.defer();
setTimeout(function () {
var countryRegions = regions[$scope.countryCode];
console.log(countryRegions);
if(countryRegions === undefined) {
deferred.resolve([]);
} else {
deferred.resolve(countryRegions);
}
}, 1000);
return deferred.promise;
};
}
WARNING: this answer was accurate when it was written, but as of 1.2 the Angular template engine does not handle promises transparently! -- @Malvolio
Yes the template engine (and expressions) handle promises transparently, but I would assign the promise to a scope property in the controller and not call everytime a function that returns a new promise (I think it's your problem, resolved promise is lost because a new promise is returned everytime).
JSFiddle: http://jsfiddle.net/YQwaf/36/
HTML:
<div ng:controller="addressValidationController">
Region Code <select ng:model="regionCode" ng:options="r.code as r.name for r in regions"/>
Country Code<select ng:model="countryCode"><option value="US">United States</option><option value="CA">Canada</option></select>
</div>
JS:
function addressValidationController($scope, $q, $timeout) {
var regions = {
US: [{
code: 'WI',
name: 'Wisconsin'},
{
code: 'MN',
name: 'Minnesota'}],
CA: [{
code: 'ON',
name: 'Ontario'}]
};
function getRegions(countryCode) {
console.log('getRegions: ' + countryCode);
var deferred = $q.defer();
$timeout(function() {
var countryRegions = regions[countryCode];
if (countryRegions === undefined) {
console.log('resolve empty');
deferred.resolve([]);
} else {
console.log('resolve');
deferred.resolve(countryRegions);
}
}, 1000);
return deferred.promise;
};
$scope.regions = [];
// Manage country changes:
$scope.$watch('countryCode', function(countryCode) {
if (angular.isDefined(countryCode)) {
$scope.regions = getRegions(countryCode);
}
else {
$scope.regions = [];
}
});
}
这篇关于Angular JS:如何绑定到承诺的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!