在$ http.get中设置变量范围值后,Ng-repeat不会更新

时间:2017-06-01 20:26:47

标签: angularjs angularjs-scope angularjs-ng-repeat

在我的AngularJS项目中,我有一个uint16_t HTML元素,应该与巴西的州绑定。所以,我正在使用ng-repeat来填充使用RESTful API从我的项目数据库加载的状态。 然后,在我的控制器中,我在名为select的范围上创建了一个变量,并为它设置了一个空数组[1]。在我调用$ http.get [2]之后,我从基数接收数据,并将其设置为$ scope.estados [3],用于ng-repeat。 [4]

控制器代码:

estados

HTML code:

myApp.controller('myCtrl', function($scope, $http, API_URL) {
    $scope.estados = []; //[1]
    $http({ // [2]
        method: 'GET',
        url:API_URL + '/estados',
        headers: {'Content-Type': 'application/x-www-form-urlencoded'}
    }).then(function(response) {
        if(response.status == 200){
            $scope.estados = response.data; // [3]
            console.log($scope.estados);
        }
    }); 
});

但是,ng-repeat不会使用新值更新。当我在<select name="uf" class="form-control" ng-model="Empresa.endereco.estado_uf"> <option ng-repeat="estado in estados" ng-value="estado.uf"> {{estado.nome}}</option> <!-- [4] --> </select> 的成功函数中调用de console.log($scope.estados);时,我可以看到$ scope使用正确的值更新,但它不会传递给View。 在设置$ scope.estados之后我已经尝试调用$http.get.then(),但我抛出错误:$scope.$apply();

如果我使用另一个值对该变量进行实例化,则绑定它,如下所示:

[$rootScope:inprog] $digest already in progress

但它永远不会更新数据库值。 我究竟做错了什么?我似乎喜欢与引用有关的东西,但我不确切知道是什么。

4 个答案:

答案 0 :(得分:2)

我有2条建议。

首先 - 不要将您的数据分配到$scope变量(对于某些上下文,请对“点规则”进行快速Google搜索)。而是将其分配给控制器代码中带有this.estados = data的控制器变量,然后使用ControllerAs变量在DOM中访问它...例如:

ng-controller="myCtrl as myCtrl"然后在DOM myCtrl.estados中而不是$scope.estados

注意:$http回调函数中,this将不再引用Controller。您需要在Controller代码的正文中存储this的引用,以便稍后引用它。我倾向于在我的所有Controller代码的顶部使用var controller = this;,因此可以在任何返回函数中轻松访问它。

第二次 ...为您的选择使用ng-options而不是转发器。它更强大,并确保正确的数据绑定。所以在你的实例中:

<select ... ng-options="estado.uf as estado.name for estado in myCtrl.estados"></select>

上面的...旨在引用select元素中您需要的任何内容,例如ng-modelclass等。

我怀疑只是转换为Dot符号而不是使用$scope可以解决这种情况......像ng-ifng-switch这样的指令(将元素从DOM中拉出来的任何东西)都可以使$scope变量无法在某种程度上无法预测。使用ng-options总是更好的做法IMO。

答案 1 :(得分:0)

我还无法测试,但如果更换引用,ngRepeat常常失去跟踪数组的功能。哪个控制器发生了什么。

您可以做的快速测试是编辑控制器以保持对同一数组的引用,并通过循环并将新结果添加到已绑定的数组来操作它。

myApp.controller('myCtrl', function($scope, $http, API_URL) {
    $scope.estados = []; //[1]
    $http({ // [2]
        method: 'GET',
        url:API_URL + '/estados',
        headers: {'Content-Type': 'application/x-www-form-urlencoded'}
    }).then(function(response) {
        if(response.status == 200){
            $scope.estados.length = 0; // truncate array
            for(var state in response.data)
               $scope.estados.push(state); // [3]

            console.log($scope.estados);
        }
    }); 
});

答案 2 :(得分:0)

您可以尝试两项更改:

1)明确设置轨道通常可以帮助ng-repeat刷新元素(即使默认情况下它已经是track by $index):

ng-repeat="estado in estados`track by $index"

2)而不是将数组分配给新数组,只需concat结果到当前空数组:

$scope.estados.concat(response.data);

答案 3 :(得分:0)

这已在许多链接中讨论过。

实际上我们应该只使用范围内的对象。原始值不会反映在消化周期中。

建议使用范围内的对象。

$scope.object= {};
$scope.object.estados = [];
$scope.object.estados = response.data; 

HTML:

<select name="uf" class="form-control" ngmodel="Empresa.endereco.estado_uf">
<option ng-repeat="estado in object.estados" ng-value="estado.uf"> 
{{estado.nome}}</option>
</select>

请阅读以下链接。

https://github.com/angular/angular.js/wiki/Understanding-Scopes