Angular JS:如何绑定到promises

时间:2012-10-23 14:45:28

标签: angularjs promise

我正在尝试将一个承诺绑定到一个视图。我不知道你是否可以直接这样做,但这就是我想要做的。我有什么想法吗?

注意:使用超时并使用静态数据时,源代码有点做作,但这样可以使代码更易于诊断。

编辑: JSFiddle页面:http://jsfiddle.net/YQwaf/27/

编辑:解决方案结果证明你可以直接绑定promises。我的原始代码有两个问题:

  1. 使用setTimeout()而不是angular的$ timeout是一个问题。 Angular不知道在触发超时时需要刷新UI(你可以用$ scope解决这个问题。$ apply在setTimeout中,或者你可以只使用$ timeout)
  2. 绑定到返回promise的函数是个问题。如果它第二次被召唤,它又是另一个承诺。更好的方法是将范围变量设置为promise,并根据需要仅创建新的promise。 (在我的情况下,这是在国家代码上调用$ scope。$ watch)
  3. 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;
        };
    }
    

4 个答案:

答案 0 :(得分:71)

从Angular 1.2开始,you can't use promises in templates directly anymore 相反,您需要将结果放入$scope then内,就像通常那样 - 没有魔力。

作为获取旧行为的临时解决方法,您可以调用

$parseProvider.unwrapPromises(true)

但稍后会删除此功能,因此请不要依赖它。

答案 1 :(得分:29)

  

警告:这个答案在编写时是准确的,但从1.2开始,Angular模板引擎无法透明地处理承诺! - @Malvolio

是的,模板引擎(和表达式)透明地处理promises,但我会将promise分配给控制器中的scope属性,而不是每次都调用一个返回新promise的函数(我认为这是你的问题,已解决的承诺丢失了因为每次都会返回一个新的承诺。

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

答案 2 :(得分:27)

从Angular 1.3开始 - $parseProvider.unwrapPromises(true) will no longer work

相反,你应该直接解开承诺:

myApiMethod().then(function(value){
    $scope.item = value; 
});

请注意,承诺展开仍然可以照常使用ngResource。

答案 3 :(得分:0)

返回对包含列表的范围变量的引用应该足够了。

function addressValidationController($scope,$timeout) {
    var regions = {
        US: [{code: 'WI',name: 'Wisconsin'}, {code: 'MN',name: 'Minnesota'}], 
        CA: [{code: 'ON',name: 'Ontario'}]
    };

    $scope._regions = [];

    $scope.getRegions = function () {

        $timeout(function () {
            var countryRegions = regions[$scope.countryCode];
            console.log(countryRegions);
            if(countryRegions === undefined) {
                $scope._regions = []
            } else {
                $scope._regions = countryRegions
            }
        }, 1000);

        return $scope._regions;
    };
}