Angular异步加载的变量未在视图中更新

时间:2014-08-14 21:43:28

标签: javascript angularjs asynchronous

我正试图让异步工作在角度,但它还没有完成工作。但差不多。

我试图将我的代码压缩到最低限度:

<div ng-controller="GeoSelectController">
    <div>
        Select country:<br/>
        <select multiple required size="10" ng-model="geoFilter" ng-options="geo.name as geo.descr for geo in geos"></select>
        <p>You selected {{geoFilter}}.</p>
    </div>
</div>

<script type="text/javascript" src="js/vendor/jQuery/jquery-2.1.1"></script>
<script type="text/javascript" src="js/vendor/angular/angular.min.js"></script>
<script type="text/javascript" src="js/customModule.js"></script>
<script type="text/javascript">

    var app = angular.module("myApp", []);
    var cm = customModule();

    app.controller("GeoSelectController", function ($scope) {
        //some starting values.
        $scope.geos = [
            {name: "DE",  descr: "Germany"},
            {name: "NL",  descr: "Netherlands"}
        ];
        $scope.geoFilter = ["NL"];

        //asynchronously get actual values.
        cm.doAsync("nrg_100a", function(error){
            if (error) {alert(error); return;}
            $scope.geos = cm.getSomeData("nrg_100a", "GEO");
        });

    });

</script>

这里的问题是cm.doAsync()部分。发生的情况是geos变量 已更新,但它未在视图中显示,直到单击选择框。我录制了一个截屏视频,以澄清:

update

(如果我点击已选择的'荷兰',则选择框的选项甚至都不会更新。)

我已经尝试将整件物品放入工厂内,但无济于事,我认为这也不是必要的。如果你认为这是关键,那么请解释为什么会这样;我非常乐意发布也失败的代码。

谢谢你们!

1 个答案:

答案 0 :(得分:2)

很可能是因为doAsync没有在角度范围内运行。工作完成后,意义digest周期没有发生。您可以使用$scope.apply()手动强制摘要周期并更新绑定来解决此问题。

    cm.doAsync("nrg_100a", function(error){
        if (error) {alert(error); return;}
        $scope.geos = cm.getSomeData("nrg_100a", "GEO");
        $scope.$apply(); //<--- here
    });

如果它正在执行异步操作(并且您可以更改自定义模块),则可以使用$q的角度版本来使用promise模式,并且您不需要执行此步骤。如果您正在进行http调用,可以使用$http并通过promise进行链接,并且一旦解析/拒绝承诺,绑定将自动更新。

创建一个服务以包装您的非角度服务: -

MyService.$inject = ['$q', '$window'];

function MyService($q, $window){

   this.getGeos = function(value1, value2) {
        var def= $q.defer();
        var cm = $window.customModule();
        cm.doAsync(value, function(error){
            if (error) {
               def.reject(error); //<-- reject the promise
            }
            var value = cm.getSomeData(value1, value2);
            def.resolve(value);
        });
      return def.promise;
   }
}

angular.module("myApp").service('MyService', MyService);

并将其用作: -

app.controller("GeoSelectController", ['$scope', 'MyService',function ($scope, myService) {
    //some starting values.
    $scope.geos = [
        {name: "DE",  descr: "Germany"},
        {name: "NL",  descr: "Netherlands"}
    ];
    $scope.geoFilter = ["NL"];
    myService.getGeos("nrg_100a", "GEO").then(function(result){
        $scope.geos = result; //set the result
    }).catch(function(error){
       alert(error); //Handle Error
    })
}]);