AngularJS实践之使用ng-repeat中$index的注意点  更新时间:2016年12月22日 17:20:23   作者:铁锚   最近通过客户的投诉主要到在ng-repeat中使用了$index引发的一个bug,下面一起来看看这个错误是如何引发的, 以及如何避免这种bug产生,然后说说我们从中得到的经验和教训。有需要的朋友们可以参考借鉴,下面来一起看看吧。 发现问题 最近有客户投诉,说在删除指定的某条记录时,结果删掉的却是另外一条记录!看起来是个很严重的BUG。 有一次我们在工作中碰到了这个问题。 要定位这个BUG非常麻烦, 因为客户也不清楚如何重现这个问题。 后来发现这个Bug是由于在 ng-repeat 中使用了 $index 引发的。 一个简单动作(action)的列表 先来看看一个完整有效的ng-repeat示例。 {{item.name}} remove 对应的控制器(controller)如下: app.controller(‘ListCtrl’, [‘$scope’, function($scope) { //items come from somewhere, from where doesn’t matter for this example $scope.items = getItems(); $scope.remove = function(index) { var item = $scope.items[index]; removeItem(item); }; }]); 看起来没什么问题,对吗? 这段代码也没有任何特别值得注意的。 添加一个过滤器(filter) 然后,让我们来做一个小小的修改: 给列表添加一个过滤器。 这是很常见的做法,如果列表很长的话,例如允许用户进行搜索。 为了方便起见, 假设我们通过 searchFilter 来查询列表中的记录。 {{item.name}} remove 控制器的代码保持不变。 看起来仍然没有问题,是吧? 事实上,有一个bug藏在里面。 如果我不说, 你能找到吗? 如果能找到,你就已经是Angular大牛了. 请尽量不要使用 $index BUG其实是在控制器里面: $scope.remove = function(index) { var item = $scope.items[index]; removeItem(item); }; 这里使用了 index参数, 然后就遇到了BUG: 过滤后的索引(indexs)不匹配原始列表的索引。 幸运的是,有一个很简单的方法来避免这种问题: 不要使用$index,而改成实际的item对象。 {{item.name}} remove 控制器如下所示: $scope.remove = function(item) { removeItem(item); }; 注意, 这里将 remove($index) 改成 remove(item) , 并修改了 $scope.remove 函数来直接操作传过来的对象。 这个小小的修改就完全避免了刚才的BUG。 为了更好地说明问题以及解决方案,请参考 interactive example 。 从中可以学到什么?       第一个教训当然是在使用 $index 要小心一点,因为以某些方式使用时很可能会产生BUG。       第二个教训是,请记住类似这样的模式,则可以用更好的做事方式,可以完全避免某些类型的BUG。 我强烈建议大家现在不要使用 $index, 从这种简单的思维转变中,就可以减少代码中的很多BUG。       第三个教训是测试并不是什么时候都有用。 即便有自动化测试,也覆盖了足够多的情形, 但对于依赖特定输入的情况,也很容易错过某些BUG。 错误本身并不是每次都会出现,即使你也用过滤来测试。       第四个教训是不要破坏抽象 —— 这一点很容易被忽略。理论上 $index 是由 ng-repeat 创建的一个 “模板变量(template variable)”。 这只在 repeat 块里面有意义(并正确起作用)。 当我们将它的值传递到外面时,它就失去了上下文从而不再有效。 如果确实想让它在 repeat 之外依然有效,则必须在控制器中也进行过滤,这就需要一些不是很必要的重复代码。 值得庆幸的是本文中介绍的模式可以用来避免这种情况。 结束语 以上就是关于AngularJS实践之ng-repeat中$index使用注意事项的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。 原文链接: AngularJS best practices: Be careful when using ng-repeat’s $index 原文日期: 2014-11-10 翻译日期: 2015-01-23 翻译人员: 铁锚 http://blog.csdn.net/renfufei 您可能感兴趣的文章: AngularJs ng-repeat 嵌套如何获取外层$index AngularJS入门(用ng-repeat指令实现循环输出 AngularJS 获取ng-repeat动态生成的ng-model值实例详解 AngularJS ng-repeat数组有重复值的解决方法 angularjs在ng-repeat中使用ng-model遇到的问题 Angularjs的ng-repeat中去除重复数据的方法 AngularJS使用ng-repeat指令实现下拉框 Angularjs中ng-repeat的简单实例 angularJS ng-repeat $index 相关文章 AngularJS实现全选反选功能 这篇文章主要介绍了AngularJS实现全选反选功能,这里用到AngularJS四大特性之二—-双向数据绑定,对angularjs实现全选反选相关知识感兴趣的朋友一起学习吧 2015-12-12 Angular.JS学习之依赖注入$injector详析 随着javaEE的spring框架的兴起,依赖注入(IoC)的概念彻底深入人心,它彻底改变了我们的编码模式和思维。在AngularJS中也有依赖注入的概念,像spring中的依赖注入,但是又有所不同。Angular中只需要在需要的地方声明一下即可,类似模块的引用,因此十分方便。 2016-10-10 详解AngularJS2 Http服务 本篇文章主要介绍了详解AngularJS2 Http服务,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 2017-06-06 详解Angular 开发环境搭建 Angular 是一款开源 JavaScript 框架,使开发和测试变得更加容易,这篇文章主要介绍了详解Angular 开发环境搭建,需要的朋友可以参考下 2017-06-06 Angular4项目中添加i18n国际化插件ngx-translate的步骤详解 这篇文章主要跟大家介绍了关于Angular4项目中添加i18n国际化插件ngx-translate的步骤,文中介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。 2017-07-07 Angularjs中使用指令绑定点击事件的方法 本篇文章主要介绍了Angularjs中使用指令绑定点击事件的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。 2017-03-03 Angular.JS读取数据库数据调用完整实例 这篇文章主要介绍了Angular.JS读取数据库数据调用,结合完整实例形式分析了AngularJS使用$http.get方法与后台php交互读取数据库数据相关操作技巧,需要的朋友可以参考下 2019-07-07 AngularJs篇:使用AngularJs打造一个简易权限系统的实现代码 本篇文章主要介绍了AngularJs篇:使用AngularJs打造一个简易权限系统的实现代码,具有一定的参考价值,有兴趣的可以了解一下。 2016-12-12 angularJS的radio实现单项二选一的使用方法 下面小编就为大家分享一篇angularJS的radio实现单项二选一的使用方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧 2018-02-02 angularjs实现下拉列表的选中事件示例 本篇文章主要介绍了angularjs实现下拉列表的选中事件示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧 2017-03-03 最新评论

发现问题

最近有客户投诉,说在删除指定的某条记录时,结果删掉的却是另外一条记录!看起来是个很严重的BUG。 有一次我们在工作中碰到了这个问题。 要定位这个BUG非常麻烦, 因为客户也不清楚如何重现这个问题。

后来发现这个Bug是由于在 ng-repeat 中使用了 $index 引发的。

一个简单动作(action)的列表

先来看看一个完整有效的ng-repeat示例。

<ul ng-controller="ListCtrl">
 <li ng-repeat="item in items">
 {{item.name}}
 <button ng-click="remove($index)">remove</button>
 </li>
</ul>

对应的控制器(controller)如下:

app.controller('ListCtrl', ['$scope', function($scope) {
 //items come from somewhere, from where doesn't matter for this example
 $scope.items = getItems();

 $scope.remove = function(index) {
 var item = $scope.items[index];
 removeItem(item);
 };
}]);

看起来没什么问题,对吗? 这段代码也没有任何特别值得注意的。

添加一个过滤器(filter)

然后,让我们来做一个小小的修改: 给列表添加一个过滤器。 这是很常见的做法,如果列表很长的话,例如允许用户进行搜索。

为了方便起见, 假设我们通过 searchFilter 来查询列表中的记录。

<ul ng-controller="ListCtrl">
 <li ng-repeat="item in items | searchFilter">
 {{item.name}}
 <button ng-click="remove($index)">remove</button>
 </li>
</ul>

控制器的代码保持不变。 看起来仍然没有问题,是吧?

事实上,有一个bug藏在里面。 如果我不说, 你能找到吗? 如果能找到,你就已经是Angular大牛了.

请尽量不要使用 $index

BUG其实是在控制器里面:

$scope.remove = function(index) {
 var item = $scope.items[index];
 removeItem(item);
};

这里使用了 index参数, 然后就遇到了BUG: 过滤后的索引(indexs)不匹配原始列表的索引。

幸运的是,有一个很简单的方法来避免这种问题: 不要使用$index,而改成实际的item对象。

<ul ng-controller="ListCtrl">
 <li ng-repeat="item in items | searchFilter">
 {{item.name}}
 <button ng-click="remove(item)">remove</button>
 </li>
</ul>

控制器如下所示:

$scope.remove = function(item) {
 removeItem(item);
};

注意, 这里将 remove($index) 改成 remove(item) , 并修改了 $scope.remove 函数来直接操作传过来的对象。

这个小小的修改就完全避免了刚才的BUG。

为了更好地说明问题以及解决方案,请参考 interactive example 。

从中可以学到什么?

      第一个教训当然是在使用 $index 要小心一点,因为以某些方式使用时很可能会产生BUG。

      第二个教训是,请记住类似这样的模式,则可以用更好的做事方式,可以完全避免某些类型的BUG。 我强烈建议大家现在不要使用 $index, 从这种简单的思维转变中,就可以减少代码中的很多BUG。

      第三个教训是测试并不是什么时候都有用。 即便有自动化测试,也覆盖了足够多的情形, 但对于依赖特定输入的情况,也很容易错过某些BUG。 错误本身并不是每次都会出现,即使你也用过滤来测试。

      第四个教训是不要破坏抽象 —— 这一点很容易被忽略。理论上 $index 是由 ng-repeat 创建的一个 “模板变量(template variable)”。 这只在 repeat 块里面有意义(并正确起作用)。 当我们将它的值传递到外面时,它就失去了上下文从而不再有效。 如果确实想让它在 repeat 之外依然有效,则必须在控制器中也进行过滤,这就需要一些不是很必要的重复代码。 值得庆幸的是本文中介绍的模式可以用来避免这种情况。

结束语

以上就是关于AngularJS实践之ng-repeat中$index使用注意事项的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

原文链接: AngularJS best practices: Be careful when using ng-repeat’s $index

原文日期: 2014-11-10

翻译日期: 2015-01-23

翻译人员: 铁锚 http://blog.csdn.net/renfufei

您可能感兴趣的文章:

  • AngularJs ng-repeat 嵌套如何获取外层$index
  • AngularJS入门(用ng-repeat指令实现循环输出
  • AngularJS 获取ng-repeat动态生成的ng-model值实例详解
  • AngularJS ng-repeat数组有重复值的解决方法
  • angularjs在ng-repeat中使用ng-model遇到的问题
  • Angularjs的ng-repeat中去除重复数据的方法
  • AngularJS使用ng-repeat指令实现下拉框
  • Angularjs中ng-repeat的简单实例
张贴在3