【问题标题】:ng-repeat not updating on update of arrayng-repeat 不更新数组的更新
【发布时间】:2015-04-24 13:51:00
【问题描述】:

我正在通过 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>

控制器(该功能在带有 ng-click 的按钮上触发):

$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 显示该数组已正确更新,但我认为该表没有更改。我不知道我做错了什么。

【问题讨论】:

  • 控制台有错误吗?你能在 plunkr 中复制吗?
  • 您的 html 是否正确绑定到控制器?

标签: angularjs


【解决方案1】:

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

为避免这种情况,我们使用 dot,例如使用“controller as”语法:

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

Edit2:我的回答不是很清楚,让我们试着深入了解发生了什么:

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

您必须记住,您的模板中不仅有 1 个作用域

例如:ng-repeat 指令为每个重复的元素创建新的作用域,但我们仍然可以在每个子作用域中访问父作用域。 Angular 使用 Prototype Inheritance 实现了这一行为:每个子作用域都通过其原型继承其父作用域的属性。

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

但是原型继承存在一个问题:假设我们有A = {}; B = {C: 1},如果A 继承自B,那么A.C == 1。但是如果我们影响一个新值A.C = 2,我们并没有改变B,只是A

Angular 表达式使用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

【讨论】:

  • @AntoineEsteve,感谢您的解释,您能帮忙解释一下为什么它在这个 plnkr 中有效吗?在这里我也更新了参考,我认为它不应该工作,但是...plnkr.co/edit/7atCfQAnTbikUaGtgYi8?p=preview
  • @huanfeng 在您的 plnkr 中,您没有覆盖子范围内的 list。您只有 2 个范围级别:控制器和 ng-repeat 子级;并且您正在更新 list 在与您用来实例化它的范围相同的范围内(控制器的范围)。所以不存在原型继承问题:您正在更新与以前相同的对象属性(相同的“$scope”对象)。表达式i in list 仍然可以按照您的意愿进行解析。
  • "$0 是 Chrome 中的选定元素" - 谢谢!从来不知道:)
【解决方案2】:

即使正确更新数组引用,我也遇到了同样的问题,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();
        });

我希望这会有所帮助。

【讨论】:

  • $scope.$apply();对我有用,谢谢#Oswaldo
  • $scope.$apply(); 拯救了我的一天
【解决方案3】:

实际上,在 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
    });
  }
};

【讨论】:

    【解决方案4】:

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

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

    通过传入containerkey,在这种情况下container 将是$scopekey 将是"dataDifferenceArray"(注意引号)。

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

    【讨论】:

    • 对我的情况有所帮助。谢谢。
    【解决方案5】:

    我什么也没做,只是在推送元素后添加了这一行“$scope.$apply()”,我就完成了。

    【讨论】:

    • 感谢您发布此答案!
    猜你喜欢
    • 2015-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-16
    • 2015-01-11
    • 1970-01-01
    • 2018-09-01
    • 2016-06-09
    相关资源
    最近更新 更多