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

Ng-repeat not updating after set variable scope value in $http.get

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

控制器代码:

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);
        }
    }); 
});

HTML代码:

<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>

但是,ng-repeat 不会更新为新值。当我在 $http.get.then() 的成功函数中调用 de console.log($scope.estados); 时,我可以看到 $scope 更新了正确的值,但它没有传递给视图。 我已经尝试在设置 $scope.estados 后调用 $scope.$apply(); 但我抛出了错误:[$rootScope:inprog] $digest already in progress.

如果我用它绑定的另一个值来实例化变量,就像这样:

$scope.estados = [
   {
      uf: 'SP',
      nome: 'São Paulo'
   }
];

但它从未使用数据库值进行更新。 我究竟做错了什么?我好像是跟参考文献相关的东西,具体是什么我也不知道

我还不能测试,但如果您替换引用,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);
        }
    }); 
});

您可以尝试两个更改:

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

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

2) 不是将数组赋给一个新数组,而是concat将结果赋给当前空数组:

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

我有 2 个建议。

首先 - 不要将数据分配给 $scope 变量(在 "The Dot Rule" 上快速 Google 搜索一些上下文).而是在控制器代码中使用 this.estados = data 将其分配给控制器变量,然后使用 ControllerAs 变量在 DOM 中访问它...例如:

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

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

Second ...为您的 select 使用 ng-options 而不是转发器。它更加健壮并确保正确的数据绑定。所以在你的例子中:

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

上面的 ... 是为了引用您在 select 元素中需要的任何其他内容,例如 ng-modelclass

我怀疑仅转换为点表示法而不是使用 $scope 将补救这种情况......像 ng-ifng-switch 这样的指令(任何将元素从 DOM) 会使 $scope 变量变得有些不可预测。在我看来,使用 ng-options 始终是更好的做法。

这已在许多 link 中讨论过。

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

建议使用Scope中的Object。

$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>

请阅读以下内容link。

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