Angular 1.6 $routeParams问题:点击账户详情出现重复项错误
嘿,我之前也踩过Angular 1.6路由参数的坑,咱们一步步来捋清楚你遇到的问题:
核心原因分析
主页能正常渲染但详情页报错,大概率是路由切换时数据没有正确重置,或者控制器复用导致旧数据残留——毕竟Angular 1.6在路由复用同一控制器时,不会重新实例化控制器,只会复用原有实例,这很容易让旧数据和新数据混在一起,触发ng-repeat的重复项错误。
具体排查&解决办法
1. 检查详情页的数据加载逻辑
你是不是在详情页控制器里用了push追加数据,而不是直接替换数组?比如:
// 错误写法:把新数据追加到旧数组里,导致重复 $scope.accounts.push(response.data); // 正确写法:直接替换数组,清空旧数据 $scope.accounts = [response.data];
主页是首次加载,数组是全新的,自然不会有重复;但详情页是在主页之后加载,如果数组没被清空,旧的列表数据+新的详情数据就会混在一起,触发重复项错误。
2. 修正track by的使用方式
用track by $index没效果?大概率是因为它不是最优解——$index只是依赖数组顺序的索引,当数组里有完全相同的对象时,Angular的脏检查还是会判定为重复绑定。建议改用数据的唯一标识,比如账户ID:
<!-- 推荐写法:用唯一ID作为跟踪标识 --> <div ng-repeat="account in accounts track by account.id">...</div>
如果你的数据没有唯一ID,那至少要确保每次进入详情页时,数组是被完全重置的(比如先$scope.accounts = []再赋值),这样track by $index才能生效。
3. 处理控制器复用的问题
如果主页和详情页用的是同一个控制器,一定要在路由切换时重置数据。可以通过监听$routeChangeSuccess事件,或者在路由的resolve里提前加载数据:
方法1:监听路由变化重置数据
app.controller('AccountController', function($scope, $routeParams, $http, $rootScope) { // 监听路由切换事件,每次切换都清空数据 $rootScope.$on('$routeChangeSuccess', function() { $scope.accounts = []; loadData(); }); function loadData() { if ($routeParams.id) { $http.get('/api/accounts/' + $routeParams.id).then(function(res) { $scope.accounts = [res.data]; }); } else { $http.get('/api/accounts').then(function(res) { $scope.accounts = res.data; }); } } // 首次加载数据 loadData(); });
方法2:用路由resolve提前加载数据
把数据加载逻辑放到路由配置里,确保进入详情页时数据是全新的:
app.config(function($routeProvider) { $routeProvider .when('/', { templateUrl: 'home.html', controller: 'AccountController', resolve: { accounts: function($http) { return $http.get('/api/accounts').then(res => res.data); } } }) .when('/account/:id', { templateUrl: 'account-detail.html', controller: 'AccountController', resolve: { accounts: function($http, $routeParams) { return $http.get('/api/accounts/' + $routeParams.id).then(res => [res.data]); } } }); }); // 控制器里直接使用resolve返回的数据 app.controller('AccountController', function($scope, accounts) { $scope.accounts = accounts; });
为什么主页能正常加载?
因为主页是你打开应用时的第一个页面,控制器是首次实例化,数组是全新的,没有任何旧数据残留,所以ng-repeat遍历的是干净的数据源,自然不会触发重复项错误。
内容的提问来源于stack exchange,提问作者Matthew White

