AngularJS全局计数器/自增ID重复错误问题排查
问题分析与解决方案
嘿,我来帮你捋捋这个问题——你以为靠唯一ID就能摆脱track by $index,结果还是踩了坑,核心问题不是ID生成逻辑的问题,而是你处理对象引用的方式出了岔子。
问题到底出在哪?
先拆解你的代码逻辑:
- 你的
helper服务生成ID的逻辑是没问题的——AngularJS的服务是单例模式,globalUniqueId会在服务初始化时创建,每次调用getNextId()都会递增,返回的确实是唯一值。 - 坑出在
anotherService.AddRecord的实现和你传递mydata的方式上:- 当你调用
anotherService.AddRecord(helper.getNextId(), mydata)时,你传的是mydata的对象引用,不是新的对象副本。 - 要是你的代码里存在重复传入同一个
mydata对象的情况(比如循环里复用了同一个对象变量),那每次调用AddRecord时,你修改的都是同一个对象的id属性,还把这个对象多次塞进myarray里。 - 最后
myarray里会有多个指向同一个对象的引用,它们的id会被最后一次赋值覆盖,导致ng-repeat识别到重复的id(多个项的id值一模一样),自然就抛出重复错误了。
- 当你调用
举个直观的例子模拟这个场景:
// 假设你这么调用: let mydata = {name: "test"}; anotherService.AddRecord(helper.getNextId(), mydata); // 此时mydata.id=1,数组里存的是这个对象 anotherService.AddRecord(helper.getNextId(), mydata); // 此时mydata.id=2,数组里的两个项的id全变成2了!
这时候数组里的两个元素其实是同一个对象,它们的id最终都是2,ng-repeat用id跟踪时当然会觉得是重复项。
怎么修复?
有两种简单的修复方式,选哪种看你的场景:
方式一:在AddRecord里创建数据副本
修改anotherService.AddRecord,每次添加时都创建mydata的副本,这样就不会修改原对象影响已经存入数组的项:
AddRecord(id, mydata){ // 用扩展运算符创建副本(ES6+支持) let newRecord = {...mydata}; // 要是环境不支持扩展运算符,就用Object.assign:let newRecord = Object.assign({}, mydata); newRecord.id = id; myarray.push(newRecord); }
方式二:确保每次传入的都是新对象
在调用AddRecord之前,每次都生成新的mydata对象,别复用同一个引用:
// 比如在循环里这么写: for (let item of someList) { // 每次都创建新对象 let mydata = {name: item.name, value: item.value}; anotherService.AddRecord(helper.getNextId(), mydata); }
验证一下
你可以在添加完数据后打印myarray看看:
console.log(myarray);
如果里面多个项的id相同,而且控制台展开后显示它们是同一个对象(内存地址一致),那就坐实了咱们的结论。
内容的提问来源于stack exchange,提问作者Dexters
相关产品推荐
相关产品推荐

