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 相关文章推荐
TinyMCE 新增本地图片上传功能
Nov 05 Javascript
js String对象中常用方法小结(字符串操作)
Jan 27 Javascript
在ASP.NET MVC项目中使用RequireJS库的用法示例
Feb 15 Javascript
javascript入门之window对象【新手必看】
Nov 22 Javascript
js实现点击每个li节点,都弹出其文本值及修改
Dec 15 Javascript
vue源码学习之Object.defineProperty 对数组监听
May 30 Javascript
vue实现文件上传功能
Aug 13 Javascript
Angular angular-file-upload文件上传的示例代码
Aug 23 Javascript
详解如何用webpack4从零开始构建react开发环境
Jan 27 Javascript
JS使用H5实现图片预览功能
Sep 30 Javascript
通过原生vue添加滚动加载更多功能
Nov 21 Javascript
jQuery与原生JavaScript选择HTML元素集合用法对比分析
Nov 26 jQuery
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
Codeigniter操作数据库表的优化写法总结
2014/06/12 PHP
ThinkPHP使用PHPExcel实现Excel数据导入导出完整实例
2014/07/22 PHP
javascript数组与php数组的地址传递及值传递用法实例
2015/01/22 PHP
PHP中实现crontab代码分享
2015/03/26 PHP
给Javascript数组插入一条记录的代码
2007/08/30 Javascript
javascript背投广告代码的完善
2008/04/08 Javascript
js 日期转换成中文格式的函数
2009/07/07 Javascript
JS 类型转换常见方法小结
2010/05/31 Javascript
jQuery1.6 使用方法一
2011/11/23 Javascript
用JavaScript计算在UTF-8下存储字符串占用字节数
2013/08/08 Javascript
js带按钮的提示框可供选择示例代码
2013/09/17 Javascript
一个简单的jquery的多选下拉框(自写)
2014/05/05 Javascript
jQuery Easyui使用(一)之可折叠面板的布局手风琴菜单
2016/08/17 Javascript
Ionic+AngularJS实现登录和注册带验证功能
2017/02/09 Javascript
vue如何在自定义组件中使用v-model
2018/05/14 Javascript
详解vue-element Tree树形控件填坑路
2019/03/26 Javascript
微信小程序BindTap快速连续点击目标页面跳转多次问题处理
2019/04/08 Javascript
基于JS实现计算24点算法代码实例解析
2020/07/23 Javascript
vue 判断元素内容是否超过宽度的方式
2020/07/29 Javascript
解决vue scoped html样式无效的问题
2020/10/24 Javascript
python实现人人网登录示例分享
2014/01/19 Python
Django的分页器实例(paginator)
2017/12/01 Python
Python爬虫包BeautifulSoup实例(三)
2018/06/17 Python
python实现微信每日一句自动发送给喜欢的人
2019/04/29 Python
详解python statistics模块及函数用法
2019/10/27 Python
Selenium及python实现滚动操作多种方法
2020/07/21 Python
爱普生美国官网:Epson美国
2018/11/05 全球购物
中国京东和泰国中央集团合资的网站:JD CENTRAL
2020/08/22 全球购物
会计职业生涯规划书
2014/01/13 职场文书
运动会闭幕式解说词
2014/02/21 职场文书
成立公司计划书
2014/05/07 职场文书
党员个人整改措施
2014/10/24 职场文书
拉贝日记观后感
2015/06/05 职场文书
幼儿园开学家长寄语(2016春季)
2015/12/03 职场文书
《草虫的村落》教学反思
2016/02/20 职场文书
Oracle11g r2 卸载干净重装的详细教程(亲测有效已重装过)
2021/06/04 Oracle