【问题标题】:angular ng-repeat track by $index$index 的角度 ng-repeat 跟踪
【发布时间】:2023-04-01 16:20:01
【问题描述】:

我很难理解为什么如果我在 ng-repeat 中使用按索引跟踪,在从数组中删除一个项目后,我会在指令范围内得到“错误”的值。

正如您在下面的 plunker 中看到的,如果我删除索引跟踪的数组中的第一个项目,指令范围内的值将不是初始值。

我期望在删除后有: 2 - b 3 - c

但我明白了 2 - 一个 3 - b

如果我不使用按索引跟踪,我会得到正确的值。

这是脚本

nsTests.controller('nsTestCtrl', ['$rootScope', '$scope', '$filter', '$timeout',
function ($rootScope, $scope, $filter, $timeout) {

    $scope.data = [
     {
         id: 1,
         name: 'a'
     },
     {
         id: 2,
         name: 'b'
     },
     {
         id: 3,
         name: 'c'
     },
    ];

    $scope.data2 = [
     {
         id: 1,
         name: 'a'
     },
     {
         id: 2,
         name: 'b'
     },
     {
         id: 3,
         name: 'c'
     },
    ];

    $scope.removeByIndex = function (index) {
        $scope.data.splice(index, 1);            
    }

    $scope.removeByItem = function (item) {
        var index = $scope.data2.indexOf(item);
        if (index !== -1) {
            $scope.data2.splice(index, 1);
        }
    }
}
]);


nsTests.directive('test', function ($compile) {
return {
    restrict: 'E',
    template: '{{value}}',
    scope: {
        data: '='
    },
    controller: function ($scope) {
        $scope.value = $scope.data.name;            
    }
};
});

这里是plunker 的问题

【问题讨论】:

  • 这似乎是您的指令的一些错误行为。如果你记录你的实际数据数组,你会看到数组实际上只剩下'b'和'c',但你的指令一直显示'a'
  • 我相信 angular 并没有通过脏检查正确检测到指令的值变化,所以你必须进行其他检查

标签: angularjs angularjs-ng-repeat angular-directive


【解决方案1】:

我认为我的plnkr 和解释将帮助您更好地理解这些东西。

这里的问题不在于track by $index

nsTests.directive('test', function ($compile) {
    return {
        restrict: 'E',
        template: '{{value}}',
        scope: {
            data: '='
        },
        controller: function ($scope) {
            $scope.value = $scope.data.name;            
        }
    };
});

您已经为您的测试指令创建了独立的范围,并且您正在将数据变量的值分配给您的测试指令的$scope.value。 指令仅编译一次,因此一旦编译,它将在父范围变量中的任何更改不影响此处之后绑定该值,因为您创建了隔离范围并从父范围复制了值。

为了更好地理解指令查看这篇文章

【讨论】:

  • 但这正是我的问题,我只需要在指令范围内有一些变量,对于我从数组中分配一个值的 plunker,但问题仍然存在于范围内的任何值指示。由于如果我不按索引使用轨道就不会发生这个问题,我相信我错过了一些东西。
  • 在这种情况下,您将直接从数组中删除,因此 ng-repeat 再次迭代列表,并且指令再次编译,因此结果符合您的预期。
  • 指令只编译一次,就是这样,否则值是正确的。
  • 当你在没有索引的情况下执行时,ng-repeat 再次使用修改后的数组进行迭代,所以它工作正常。
  • 我相信问题是通过使用按索引跟踪,角度将重用节点。由于我需要列表中的重复值,因此我需要创建一个“唯一”id 并通过它进行跟踪。
【解决方案2】:

使用track by index,angular会重用节点

这实际上就是问题所在;该指令未重新初始化,因为 Angular 似乎忽略了它的值参数并保留索引中的原始数据。

例如

var arr = [
  { id: 0, status: "Pass" },
  { id: 1, status: "Fail" }
];

如果您重复此数据并在重复中有一个自定义指令,该指令将显示一个绿点表示通过,一个红点表示失败。

示例:https://plnkr.co/edit/ytQ9p6YJOfrDubCGIc2N?p=preview

.pass {
  color: green;
}

.fail {
  color: red
}

.pass,
.fail {
  font-size: 24px;
}
<table>
  <th>ID</th>
  <th>Status</th>
  <tr>
    <td>1</td>
    <td class="pass">&squf;</td>
  </tr>
  <tr>
    <td>2</td>
    <td class="fail">&squf;</td>
  </tr>
</table>

当应用过滤器时,例如通过 arr 上的 $filter 过滤掉 ID:1 的对象

.pass {
  color: green;
}

.fail {
  color: red
}

.pass,
.fail {
  font-size: 24px;
}
<table>
  <th>ID</th>
  <th>Status</th>
  <tr>
    <td>2</td>
    <td class="pass">&squf;</td>
  </tr>
</table>

如您所见,1 已被过滤掉,但现在结果不正确。这是因为 Angular 有点懒惰并且没有重新初始化我们正在使用的指令,即使我们传入的数据现在不同了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-01
    • 1970-01-01
    • 2014-12-31
    • 2017-04-12
    相关资源
    最近更新 更多