如何强制 ngRepeat 不通过引用进行比较?
How do I force ngRepeat to not compare by reference?
在指令中,我使用 ngRepeat
从作用域上的参数化函数获取其项目。
以简化的方式,它看起来像这样:
<div data-ng-repeat="data in containerItems">
<div data-ng-repeat="myItem in getItems(data) track by myItem.Id">
<!-- some content -->
</div>
</div>
我的问题是我似乎无法摆脱以下异常:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
据我根据其他几个问题(例如 this, or )得出的结论,ngRepeat
似乎认为每次重新请求项目时都会更新,导致提示又一个摘要循环,最终以连续太多而放弃。
特别是,one comment by user g00fy was insightful to me: Indeed, I am using lodash's _.map
function 生成 ngRepeat
显示的项目列表,从而在每次 ngRepeat
重新请求其项目时创建新的对象实例。
起初,我认为我可以通过将我的项目生成函数的 return 值保存到作用域上的一个变量中来解决这个问题。这消除了上述错误。
不幸的是,这对我来说不是一个合适的解决方案,因为范围由我的指令的多个实例共享,其中使用了 ngRepeat
。我真的需要每个 ngRepeat
使用适当的参数从生成函数中检索项目。
一开始我用的是
track by $index
但我也试过
track by myItem.Id
我曾希望这会强制 ngRepeat
假定仅当 ID 更改时才更改项目。但是,none 似乎可以防止上述异常的发生。
有什么方法可以强制 AngularJS 仅在 值 发生变化时才考虑 ngRepeat
中发生变化的项目,而不是实例?
在结构上,getItems(data)
的 return 值似乎可以保存在 data
上。但是,我正在处理的应用程序框架中的代码(这意味着它的行为与应用程序的许多模块所依赖的一样,不得更改)将直接采用包含 data
的对象图并将其发送到服务器端后端。因此,data
不是计算运行时数据的正确位置。
为了提供一个更完整的示例,getItems
函数大致如下所示:
$scope.getItems = function (data) {
var itemSet = itemSets[data.itemSetId];
if (itemSet.customItems) {
return itemSet.customItems.slice(1);
} else {
return _.map(standardItems.slice(1), function (si) {
return {
Id: si.code,
Name: si.Description + ' ' + si.Owner
};
});
}
};
此处的细节无关紧要。重要的部分是我根据参数 data
中的内容从其他地方检索项目,然后这些项目的格式可能需要转换为由我的 ngRepeat
处理的规范格式-编辑模板。
所以,我知道你有一个复杂的机制来获取你的数据,你需要在很多 ng-repeat
之间共享。
因为脏检查与 angularJS 一起工作的方式(保持值和 $scope 值之间的简单 ===),您必须将 ng-repeat
分配给单个引用(然后使用如果集合更新,则为不可变对象)。
您是否无法执行以下操作来获取数据?
myItems = {};
$scope.getItems = function (data) {
if(!myItems[data.itemSetId]) {
var itemSet = itemSets[data.itemSetId];
if (itemSet.customItems) {
myItems[data.itemSetId] = itemSet.customItems.slice(1);
} else {
myItems[data.itemSetId] _.map(standardItems.slice(1), function (si) {
return {
Id: si.code,
Name: si.Description + ' ' + si.Owner
};
});
}
}
return myItems[data.itemSetId];
};
- 如果
getItems(data)
永远不变,您可以使用一次性绑定:ng-repeat="a in ::getItems(data)"
- 如果它发生变化,您应该将其结果存储在 $scope 中并手动更新它——这可能是最好的方法。在 ng-repeat 中使用方法是一种糟糕的风格,很可能会在以后导致性能问题。所以,这看起来像:
<div data-ng-repeat="myItem in myItems track by myItem.Id">
$scope.myItems = getItems(data);
//somewhere you need to update myItems -- can be not easy
你的问题是你的 getItems 不应该创建对象,所以你可以通过缓存对象或完整结果来修复它(参见 Deblaton 回答),但这在 general.So 中是不好的,这看起来像:
<div data-ng-repeat="myItem in getItems(data) track by myItem.Id">
$scope.objectCache = {};
$scope.getItems = function (data) {
var itemSet = itemSets[data.itemSetId];
if (itemSet.customItems) {
return itemSet.customItems.slice(1);
} else {
return _.map(standardItems.slice(1), function (si) {
if (!objectCache[si.code]) {
objectCache[si.code] = {
Id: si.code,
Name: si.Description + ' ' + si.Owner
};
}
return objectCache[si.code];
});
}
};
在指令中,我使用 ngRepeat
从作用域上的参数化函数获取其项目。
以简化的方式,它看起来像这样:
<div data-ng-repeat="data in containerItems">
<div data-ng-repeat="myItem in getItems(data) track by myItem.Id">
<!-- some content -->
</div>
</div>
我的问题是我似乎无法摆脱以下异常:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
据我根据其他几个问题(例如 this, or ngRepeat
似乎认为每次重新请求项目时都会更新,导致提示又一个摘要循环,最终以连续太多而放弃。
特别是,one comment by user g00fy was insightful to me: Indeed, I am using lodash's _.map
function 生成 ngRepeat
显示的项目列表,从而在每次 ngRepeat
重新请求其项目时创建新的对象实例。
起初,我认为我可以通过将我的项目生成函数的 return 值保存到作用域上的一个变量中来解决这个问题。这消除了上述错误。
不幸的是,这对我来说不是一个合适的解决方案,因为范围由我的指令的多个实例共享,其中使用了 ngRepeat
。我真的需要每个 ngRepeat
使用适当的参数从生成函数中检索项目。
一开始我用的是
track by $index
但我也试过
track by myItem.Id
我曾希望这会强制 ngRepeat
假定仅当 ID 更改时才更改项目。但是,none 似乎可以防止上述异常的发生。
有什么方法可以强制 AngularJS 仅在 值 发生变化时才考虑 ngRepeat
中发生变化的项目,而不是实例?
在结构上,getItems(data)
的 return 值似乎可以保存在 data
上。但是,我正在处理的应用程序框架中的代码(这意味着它的行为与应用程序的许多模块所依赖的一样,不得更改)将直接采用包含 data
的对象图并将其发送到服务器端后端。因此,data
不是计算运行时数据的正确位置。
为了提供一个更完整的示例,getItems
函数大致如下所示:
$scope.getItems = function (data) {
var itemSet = itemSets[data.itemSetId];
if (itemSet.customItems) {
return itemSet.customItems.slice(1);
} else {
return _.map(standardItems.slice(1), function (si) {
return {
Id: si.code,
Name: si.Description + ' ' + si.Owner
};
});
}
};
此处的细节无关紧要。重要的部分是我根据参数 data
中的内容从其他地方检索项目,然后这些项目的格式可能需要转换为由我的 ngRepeat
处理的规范格式-编辑模板。
所以,我知道你有一个复杂的机制来获取你的数据,你需要在很多 ng-repeat
之间共享。
因为脏检查与 angularJS 一起工作的方式(保持值和 $scope 值之间的简单 ===),您必须将 ng-repeat
分配给单个引用(然后使用如果集合更新,则为不可变对象)。
您是否无法执行以下操作来获取数据?
myItems = {};
$scope.getItems = function (data) {
if(!myItems[data.itemSetId]) {
var itemSet = itemSets[data.itemSetId];
if (itemSet.customItems) {
myItems[data.itemSetId] = itemSet.customItems.slice(1);
} else {
myItems[data.itemSetId] _.map(standardItems.slice(1), function (si) {
return {
Id: si.code,
Name: si.Description + ' ' + si.Owner
};
});
}
}
return myItems[data.itemSetId];
};
- 如果
getItems(data)
永远不变,您可以使用一次性绑定:ng-repeat="a in ::getItems(data)"
- 如果它发生变化,您应该将其结果存储在 $scope 中并手动更新它——这可能是最好的方法。在 ng-repeat 中使用方法是一种糟糕的风格,很可能会在以后导致性能问题。所以,这看起来像:
<div data-ng-repeat="myItem in myItems track by myItem.Id"> $scope.myItems = getItems(data); //somewhere you need to update myItems -- can be not easy
你的问题是你的 getItems 不应该创建对象,所以你可以通过缓存对象或完整结果来修复它(参见 Deblaton 回答),但这在 general.So 中是不好的,这看起来像:
<div data-ng-repeat="myItem in getItems(data) track by myItem.Id"> $scope.objectCache = {}; $scope.getItems = function (data) { var itemSet = itemSets[data.itemSetId]; if (itemSet.customItems) { return itemSet.customItems.slice(1); } else { return _.map(standardItems.slice(1), function (si) { if (!objectCache[si.code]) { objectCache[si.code] = { Id: si.code, Name: si.Description + ' ' + si.Owner }; } return objectCache[si.code]; }); } };