[TOC]
# ng-repeat指令
## 简介
使用指令复制元素在构建模板内容的过程中,有时需要反复将不同的数据加载到一个元素中,例如,通过`<li>`元素绑定一个数组的各成员。此时,可以使用“ng-repeat”指令,它的功能是根据绑定数组成员的数量,复制页面中被绑定的`<li>`元素,并在复制过程中添加元素相应的属性和方法,通过这种方式,实现数组数据与元素绑定的过程。在使用“ng-repeat”指令复制元素的过程中,还提供了几个非常实用的专有变量,可以通过这些变量来处理显示数据时的各种状态。
* $first,该变量表示记录是否是首条,如果是则返回true,否则返回false。
* $last,该变量表示记录是否是尾条,如果是则返回true,否则返回false。
* $middle,该变量表示记录是否是中间条,如果是则返回true,否则返回false。
* $index,该变量表示记录的索引号,其对应的值从0开始。
* $even,该变量表示记录是否是奇数条,如果是则返回true,否则返回false。
* $odd,该变量表示记录是否是偶数条,如果是则返回true,否则返回false。
## 基本使用
~~~html
<ul>
<!--data为$scope中的数组-->
<!--in为关键字-->
<!--item为一个变量名,代表data里面的每一个元素-->
<li ng-repeat="item in data">
{{item.name}}
{{item.sex}}
{{item.age}}
{{item.score}}
</li>
</ul>
~~~
## 使用ng-repeat需要注意的问题
在Angular中,ng-repeat是一个非常重要的内部指令,它的功能是在遍历数组过程中生成DOM元素,实现在页面中展示列表数据中的功能,功能强大、使用简单,但如果使用不当也容易出现一些问题,具体表现如下。
* 在使用过程中,如果有过滤器时,调用$index并不能准确定位到对应的记录。
* 在调用ng-repeat指令重新请求数据,并不是在原来DOM元素中更新数据,而是再次新建DOM元素。
* 在通过ng-repeat指令生成的子元素中,如果通过父的scope对象更新数据时,不能直接更新遍历的数组源,而必须逐个更新。
## 使用ng-repeat处理办法
### 有过滤器的情况下使用ng-repeat
### 首先数据会都自带不重复的id
### 在界面显示的情况下,也会使用赋值表达式【item in localData=(data | filter:myfilter) 】
#### index.js
~~~js
//创建控制器
angular.module('myapp').controller('my_c', ['$filter', '$scope', function ($filter, $scope) {
// 数据
// 一般情况下,我们的数据都会带有独立的ID
$scope.data = [
{
id: 1,
name: 'hzj',
sex: '男',
age: 18,
score: 100
},
{
id: 2,
name: 'hzj',
sex: '男',
age: 28,
score: 100
},
{
id: 3,
name: 'hzj',
sex: '男',
age: 26,
score: 100
},
{
id: 4,
name: 'hzj',
sex: '男',
age: 30,
score: 100
},
{
id: 5,
name: 'hzj',
sex: '男',
age: 19,
score: 100
},
{
id: 6,
name: 'hzj',
sex: '男',
age: 22,
score: 100
},
{
id: 7,
name: 'hzj',
sex: '男',
age: 18,
score: 100
},
{
id: 8,
name: 'hzj',
sex: '男',
age: 21,
score: 100
},
{
id: 9,
name: 'hzj',
sex: '男',
age: 18,
score: 100
}
];
//自定义一个filter过滤器的过滤规则
$scope.myfilter = function (item) {
return item.age > 25;
};
// 删除元素
// item参数为view传递过来的数据里面的某一项
$scope.removeItem = function (item) {
//使用angular.forEach方法查询到数组中对应的下
//arrayItem为$scope.data里面的每一项
// index为arrayItem项在$scope.data中的下标
angular.forEach($scope.data, function (arrayItem, index) {
if (item.id === arrayItem.id) {
//找到元素对应的下标,然后删除元素
$scope.data.splice(index, 1);
return;
}
});
};
}]);
~~~
#### index.html
~~~html
<!DOCTYPE html>
<!--加载模块-->
<html lang="en" ng-app="myapp">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--加载样式-->
<link rel="stylesheet" href="css/index.css">
<!--加载Angular类库-->
<script src="bower_components/angular/angular.min.js"></script>
<!--加载模块创建文件-->
<script src="js/app.js"></script>
<!--加载控制器创建文件-->
<script src="js/index.js"></script>
</head>
<body>
<!--加载控制器-->
<div ng-controller="my_c">
<!--带过滤的数据-->
<table>
<thead>
<tr>
<td>行标</td>
<td>id</td>
<td>姓名</td>
<td>性别</td>
<td>年龄</td>
<td>分数</td>
<td>操作</td>
</tr>
</thead>
<tbody>
<!--这里使用了过滤好的数据,原数据为data-->
<!--localData=( data |filter:myfilter)-->
<tr ng-repeat="item in localData =( data |filter:myfilter) ">
<td>{{$index}}</td>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.sex}}</td>
<td>{{item.age}}</td>
<td>{{item.score}}</td>
<td>
<button ng-click="removeItem(item)">删除</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="7">总人数为:{{localData.length}}</td>
</tr>
</tfoot>
</table>
<hr>
<!--原始数据-->
<table>
<thead>
<tr>
<td>行标</td>
<td>id</td>
<td>姓名</td>
<td>性别</td>
<td>年龄</td>
<td>分数</td>
</tr>
</thead>
<tbody>
<!--这里使用的是原数据-->
<tr ng-repeat="item in data">
<td>{{$index}}</td>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.sex}}</td>
<td>{{item.age}}</td>
<td>{{item.score}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="6">总人数为:{{data.length}}</td>
</tr>
</tfoot>
</table>
</div>
</body>
</html>
~~~
#### 结果
![](https://box.kancloud.cn/2016-09-10_57d3f729162f3.png)
#### 点击删除ID为3的元素之后
![](https://box.kancloud.cn/2016-09-10_57d3f72aaa88b.png)
### 使用track by排序数据中的唯一id属性
在使用ng-repeat指令显示列表数据时,如果需要更新数据,那么页面中原有的DOM元素在更新过程中并不会被重用,而是会被删除,再重新生成与上次结构一样的元素。反复生成DOM元素对页面的加载来说,并不是一件好事,它不仅会延迟数据加载的速度,而且非常浪费页面资源。为了解决这种现象,我们在使用ng-repeat指令更新数据时,需要使用track by对数据源进行排序,排序的字段为不可重复的id。放心每个数据库里面的数据都会有id属性
~~~html
<tr ng-repeat="item in localData =( data |filter:myfilter | orderBy:'-age' ) track by item.id">
<td>{{$index}}</td>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.sex}}</td>
<td>{{item.age}}</td>
<td>{{item.score}}</td>
<td>
<button ng-click="removeItem(item)">删除</button>
</td>
</tr>
~~~
~~~html
<tr ng-repeat="item in data track by item.id">
<td>{{$index}}</td>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.sex}}</td>
<td>{{item.age}}</td>
<td>{{item.score}}</td>
</tr>
~~~
### ng-repeat结束事件【这里仅仅是参考,到了中级部分会出现自定义指令】
Angular并没有ng-repeat结束事件监听,我们必须自己自定义一个指令来完成
~~~js
//自定义指令repeatFinish
angular.module('myapp').directive('hzjEndRepeat', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
//scope为repeat出来的每个dom的作用域
//element为repeat当前的元素
//attr为属性
if (scope.$last === true) {
//延迟一些执行
$timeout(function () {
//像父亲发送事件
$scope.$emit('hzjEndRepeat');
});
}
}
};
}]);
~~~
~~~html
<div class="filter_row clearfix" ng-repeat="item in filterType" hzj-end-repeat>
</div>
~~~
- Angular简介
- angular1资料网站
- Angular初级部分
- 打破传统的前端
- Angular基本组成部分
- Angular环境搭建
- Angular项目测试
- Angular基础概念
- Angular模块
- Angular控制器
- Angular指令
- Angular表达式
- Angular视图
- Angular基础实战
- Angular模块创建和使用
- Angular控制器和模型创建
- scope对象
- 控制器中调度window对象和document对象
- Angular表达式调度过滤器
- Angular中的ng模块全局方法
- Angular模板应用
- 使用指令复制元素
- 使用指令隐藏显示元素
- Angular指令ng-if
- ng-src和ng-href
- Angular处理样式
- Angular作用域事件传递
- 表单中的元素
- Angular初学者常见的坑
- 再论双向绑定
- Angular中级部分
- Angular路由机制
- ui-router管理状态
- ui-router状态嵌套和视图嵌套
- ui-router多个命名的视图
- ui-router路由控制
- 自定义指令
- 自定义过滤器
- Angular项目目录结构
- Angular服务
- Angular高级部分
- Angular依赖注入
- README