ng-repeat不更新数组更新

时间:2015-04-24 13:51:01

标签: angularjs

我通过ng-repeat循环渲染数据。我想在更新阵列时更新它。从我读到的,这应该自动发生,但这不起作用。我做错了什么?

html:

<tr ng-repeat="data in dataDifferenceArray">
    <td>
      {{data.name}}
    </td>
    <td>
      {{data.startData}}
    </td>
    <td>
      {{data.endData}}
    </td>
    <td>
      {{data.differenceData}}
    </td>
</tr>

控制器(此功能在按钮点击时触发):

$scope.getDifferences = function () {
  $scope.dataDifferenceArray = [];
  var i;
  for (i = 0; i < 20 ;i++) {
    $scope.dataDifferenceArray.push({
      name : 30,
      startData : 20,
      endData : 2,
      differenceData : 30
    })
  }
}

Console.log显示数组已正确更新,但我视图中的表不会更改。我不知道我做错了什么。

5 个答案:

答案 0 :(得分:53)

那是因为您更改了方法getDifferences中的数组引用。

为避免这种情况,我们,例如使用“控制器为”语法:

<div ng-controller="myController as c">
    [...]

    <tr ng-repeat="data in c.dataDifferenceArray">
        <td>
          {{data.name}}
        </td>
        <td>
          {{data.startData}}
        </td>
        <td>
          {{data.endData}}
        </td>
        <td>
          {{data.differenceData}}
        </td>
    </tr>
    [...]

如果你想了解范围是如何工作的,我会建议这篇文章:https://github.com/angular/angular.js/wiki/Understanding-Scopes#ngRepeat

另一种解决方案可能是:

$scope.getDifferences = function () {
  $scope.dataDifferenceArray.length = 0; // here ----
  var i;
  for (i = 0; i < 20 ;i++) {
    $scope.dataDifferenceArray.push({
      name : 30,
      startData : 20,
      endData : 2,
      differenceData : 30
    })
  }
}

但在此解决方案中,您需要在外部创建数组(并且只需创建一次):$scope.dataDifferenceArray = [];

编辑2:我的回答并不是很清楚,让我们试着深入了解正在发生的事情:

问: 为什么ng-repeat仍然有引用REFERENCE1?

您必须记住模板中不仅有1个范围

例如:ng-repeat指令为每个重复元素创建新范围,但我们仍然可以访问每个子范围中的父范围。 Angular使用原型继承实现了这种行为:由于其原型,每个子范围都继承其父范围的属性。

您可以通过检查子元素上的元素来测试它的工作方式,然后在控制台中输入:$($0).scope()(它将为您提供所选元素的范围,$0是所选元素(铬))。您现在可以看到$($0).scope().$parent$($0).scope().__proto__中存在相同的对象,它是您的父作用域。

但是原型继承存在一个问题:假设我们A = {}; B = {C: 1}A继承自B然后A.C == 1。但是,如果我们影响新值A.C = 2,我们就不会更改B,只会更改A

使用当前作用域this评估角度表达式。因此,如果我们有类似ng-click="dataDifferenceArray = []"的内容,则相当于this.dataDifferenceArray = [],其中thisng-click所在元素的范围。

当您使用 controller-as 时会解决此问题,因为它会在范围内注入控制器,并且您永远不会直接影响范围的属性。

让我们回顾一下我们的示例:A = {}; B = {C: {D: 1}},如果A继承自B,那么A.C.D == 1。现在即使我们影响了新值A.C.D = 2,我们也改变了B

答案 1 :(得分:15)

即使正确更新数组引用,我也遇到了同样的问题,ng-repeat没有呈现我的更改。最后,我通过调用$ scope。$ apply();

找到了解决方案
$window.wizard.on("readySubmit", function () {
            var newArray = GenesisFactory.GetPermissionsFromTemplate(GenesisFactory.SecurityModules, true);
            $scope.NewSecurityProfileInstance.Permission.length = 0;
            newArray.forEach(function (entry) {
                $scope.NewSecurityProfileInstance.Permission.push(entry);
            });
            $scope.$apply();
        });

我希望这可以提供帮助。

答案 2 :(得分:5)

我没有做任何事情,只是添加了这一行&#34; $ scope。$ apply() &#34;推完元素之后,我就完成了。

答案 3 :(得分:3)

对于那些在范围内设置数组的人(即$scope.$apply()如果在推送后调用会导致错误),但无法在DOM上正确更新,我的解决方法在推/片/数组更新后立即调用此函数:

function applyArray(container, key) {
    setTimeout(function() {
        var tempArray = container[key];
        container[key] = [];
        $scope.$apply();
        container[key] = tempArray;
        $scope.$apply();
    }, 0);
}

通过传递containerkeycontainer在这种情况下$scopekey将是"dataDifferenceArray"(注意引号)。

我不知道为什么在某些情况下DOM没有正确更新。它显示了正确的元素数量,并且在添加新元素时更新,它只是不正确地更新子元素DOM(即新推送的元素可以采用前一个子元素的DOM视图)。这可能是由于我们如何在Johnpapa's Angular Style Guide中将this重新定义为vm,但我对此并不自信。

答案 4 :(得分:0)

实际上看起来你的数组在click函数中被设置为空。如果将数组范围移到函数外部,这将起作用。

实施例

// Declared outside
$scope.dataDifferenceArray = [];

// Your function
$scope.getDifferences = function () {
  var i;
  for (i = 0; i < 20 ;i++) {
    $scope.dataDifferenceArray.push({
      name : 30,
      startData : 20,
      endData : 2,
      differenceData : 30
    });
  }
};