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 相关文章推荐
jQuery 源码分析笔记(6) jQuery.data
Jun 08 Javascript
ajax处理php返回json数据的实例代码
Jan 24 Javascript
页面右下角弹出提示框示例代码js版
Aug 02 Javascript
让复选框只能选择一项的方法
Oct 08 Javascript
学习JavaScript设计模式之迭代器模式
Jan 19 Javascript
解决angular2 获取到的数据无法实时更新的问题
Aug 31 Javascript
4 种滚动吸顶实现方式的比较
Apr 09 Javascript
基于mpvue小程序使用echarts画折线图的方法示例
Apr 24 Javascript
详解Vue demo实现商品列表的展示
May 07 Javascript
JavaScript实现页面中录音功能的方法
Jun 04 Javascript
原生js实现针对Dom节点的CRUD操作示例
Aug 26 Javascript
利用JavaScript为句子加标题的3种方法示例
Jan 05 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 download.php实现代码 跳转到下载文件(response.redirect)
2009/08/26 PHP
php教程之phpize使用方法
2014/02/12 PHP
网页常用特效代码整理
2006/06/23 Javascript
动态样式类封装JS代码
2009/09/02 Javascript
JavaScript运动减速效果实例分析
2015/08/04 Javascript
jquery实现Li滚动时滚动条自动添加样式的方法
2015/08/10 Javascript
在Ubuntu系统上安装Node.JS的教程
2015/10/15 Javascript
JavaScript如何禁止Backspace键
2015/12/02 Javascript
javascript特殊文本输入框网页特效
2016/09/13 Javascript
JavaScript reduce和reduceRight详解
2016/10/24 Javascript
详解JavaScript常量定义
2017/01/03 Javascript
Node.js读取文件内容示例
2017/03/07 Javascript
vue.js的安装方法
2017/05/12 Javascript
AngularJS全局警告框实现方法示例
2017/05/18 Javascript
详述 Sublime Text 打开 GBK 格式中文乱码的解决方法
2017/10/26 Javascript
浅析vue 函数配置项watch及函数 $watch 源码分享
2018/11/22 Javascript
微信小程序实现张图片合成为一张并下载
2019/07/16 Javascript
[02:16]DOTA2英雄基础教程 干扰者
2014/01/15 DOTA
[01:09]2014DOTA2国际邀请赛 TI4西雅图DOTA2 中国美女coser加油助威
2014/07/20 DOTA
在Python的Django框架中实现Hacker News的一些功能
2015/04/17 Python
python基于BeautifulSoup实现抓取网页指定内容的方法
2015/07/09 Python
深入理解NumPy简明教程---数组2
2016/12/17 Python
django定期执行任务(实例讲解)
2017/11/03 Python
python三方库之requests的快速上手
2019/03/04 Python
viagogo波兰票务平台:演唱会、体育比赛、戏剧门票
2018/04/23 全球购物
Carolina Lemke Berlin澳大利亚官网:时尚太阳镜品牌
2019/09/17 全球购物
blueseventy官网:铁人三项和比赛泳衣
2021/02/06 全球购物
自荐信不宜过于夸大
2013/11/06 职场文书
好家长事迹材料
2014/01/23 职场文书
机关门卫制度
2014/02/01 职场文书
兰兰过桥教学反思
2014/02/08 职场文书
2014村务公开实施方案
2014/02/25 职场文书
竞选学生会演讲稿
2014/04/25 职场文书
2016年公司中秋节致辞
2015/11/26 职场文书
jQuery class属性操作addClass()与removeClass()、hasClass()、toggleClass()
2021/03/31 jQuery
MySQL系列之八 MySQL服务器变量
2021/07/02 MySQL