AngularJS实践之使用ng-repeat中$index的注意点


Posted in Javascript onDecember 22, 2016

发现问题

最近有客户投诉,说在删除指定的某条记录时,结果删掉的却是另外一条记录!看起来是个很严重的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

Javascript 相关文章推荐
javascript Xml增删改查(IE下)操作实现代码
Jan 30 Javascript
Array的push与unshift方法性能比较分析
Mar 05 Javascript
jQuery中使用了document和window哪些属性和方法小结
Sep 13 Javascript
JavaScript入门之对象与JSON详解
Oct 21 Javascript
jquery 页面滚动到底部自动加载插件集合
Jan 31 Javascript
js继承call()和apply()方法总结
Dec 08 Javascript
jQuery中常用的遍历函数用法实例总结
Sep 01 Javascript
jQuery实现简单倒计时功能的方法
Jul 04 Javascript
JS实现发送短信验证后按钮倒计时功能(防止刷新倒计时失效)
Jul 07 Javascript
详解vue组件开发脚手架
Jun 15 Javascript
微信小程序录音实现功能并上传(使用node解析接收)
Feb 26 Javascript
Angular短信模板校验代码
Sep 23 Javascript
JS中微信小程序自定义底部弹出框
Dec 22 #Javascript
Bootstrap源码解读表单(2)
Dec 22 #Javascript
javascript学习之json入门
Dec 22 #Javascript
Bootstrap源码解读网格系统(3)
Dec 22 #Javascript
js微信支付实现代码
Dec 22 #Javascript
jquery自定义插件结合baiduTemplate.js实现异步刷新(附源码)
Dec 22 #Javascript
Html中 IFrame的用法及注意点
Dec 22 #Javascript
You might like
PHP使用SOAP调用.net的WebService数据
2013/11/12 PHP
ThinkPHP多语言支持与多模板支持概述
2014/08/22 PHP
详解PHP处理密码的几种方式
2016/11/30 PHP
php封装单文件上传到数据库(路径)
2017/10/15 PHP
转自Jquery官方 jQuery1.1.3发布,速度提升800%,体积保持20K
2007/08/19 Javascript
div+css布局的图片连续滚动js实现代码
2010/05/04 Javascript
myFocus slide3D v1.1.0 使用方法与下载
2011/01/12 Javascript
基于jquery的web页面日期格式化插件
2011/11/15 Javascript
js Dialog 实践分享
2012/10/22 Javascript
Node.js模拟浏览器文件上传示例
2014/03/26 Javascript
jquery对table中各数据的增加、保存、删除操作示例
2014/05/14 Javascript
开源的javascript项目Kissy介绍
2014/11/28 Javascript
javascript实现随机显示星星特效
2016/01/28 Javascript
微信小程序 教程之事件
2016/10/18 Javascript
yarn与npm的命令行小结
2016/10/20 Javascript
利用Js的console对象,在控制台打印调式信息测试Js的实现
2016/11/26 Javascript
jQuery插件zTree实现单独选中根节点中第一个节点示例
2017/03/08 Javascript
在vue中使用公共过滤器filter的方法
2018/06/26 Javascript
微信小程序scroll-view实现滚动穿透和阻止滚动的方法
2018/08/20 Javascript
React实现全选功能
2020/08/25 Javascript
[04:14]从西雅图到上海——玩家自制DOTA2主题歌曲应援TI9
2019/07/11 DOTA
Pyramid将models.py文件的内容分布到多个文件的方法
2013/11/27 Python
Python正则表达式非贪婪、多行匹配功能示例
2017/08/08 Python
linux环境下的python安装过程图解(含setuptools)
2017/11/22 Python
Tensorflow矩阵运算实例(矩阵相乘,点乘,行/列累加)
2020/02/05 Python
Python sorted排序方法如何实现
2020/03/31 Python
完美解决python针对hdfs上传和下载的问题
2020/06/05 Python
如何向接受结构参数的函数传入常数值
2016/02/17 面试题
社区八一活动方案
2014/02/03 职场文书
粗加工管理制度
2014/02/04 职场文书
优秀医生事迹材料
2014/02/12 职场文书
副科级后备干部考察材料
2014/05/15 职场文书
蛋糕店创业计划书范文
2014/09/21 职场文书
师德标兵先进事迹材料
2014/12/19 职场文书
高中生综合素质自我评价
2015/03/06 职场文书
利用Python实现模拟登录知乎
2022/05/25 Python