使用 ngRepeat
指令的时候,我们一般会通过 $index
获取当前层级的每一项循环的索引,但是当我们循环出来的数据中还有数组(数组A)需要我们循环的话,我们还是会使用 ngRepeat
来循环我们这个数组。但是这个时候,假如我们还需要数组A中的每一项的索引来做一些操作的话,这个时候我们就不能使用刚才的哪个 $index
,这个时候我们应该怎么办呢?这个时候就需要使用另外一个指令 ngInit
设置一个变量来保存我们每个循环的索引 $index
,这样就可以继续操作了,详细的过程参见下文。
在线的 demo 原文的链接 angular-china
我们先来看一个数据对象,如下:
var appData = [ { name: 'C++从入门到放弃', author: 'dreamapple', books: [ {name: 'github'}, {name: 'google'}, {name: 'nodejs'}, {name: 'react'} ] }, { name: 'Java从入门到跑路', author: '呵呵哒', books: [ {name: '雪碧'}, {name: '百事可乐'}, {name: '鸡尾酒'} ] } ];
现在有这么一个要求,我需要将上面的那个 appData
循环出来,其中还要循环出来 books
里面的每一项,然后每一个 books
里面的每一项都可以进行删除,也可以给每一个 books
数组里面添加新的一项。
(1)循环出来这个 appData
数据还是很容易的,通过嵌套的 ngRepeat
很方便的就可以搞定了。
(2)关于嵌套我们能够使用的索引是 $index
,但是两层以上的话,如果每一层嵌套都使用 $index
作为索引的话,势必会引起混乱。这个时候就需要我们想一些办法去得到每一层的索引。
(3)我们目前比较好的一个做法就是通过 ngInit
指令,然后在循环开始的时候将每一层的索引保存在一个变量中,然后就可以在循环的不同层级之间使用了。
(4)我们还需要定义另一个数组 vm.tempItem
,这个数组也用于循环,循环出来的每一项用作被添加项的数据模型。
注意:循环 books
数组我们还有一些需要注意的地方,我们要使用 track by
语法,不然每次增加或者删除 books
里面的内容时, books
每一项的 $index
不会发生变化,那么就不好进行删除操作了。
我把里面的重点部分单独拿了出来,然后大家一起来看一看:页面部分:
<ul class="list-group" ng-repeat="item in vm.appData" ng-init="outerIndex = $index"> <h3>{{item.name}}<span class="outer-index">outerIndex:{{outerIndex}}</span></h3> <h4>{{item.author}}</h4> <li class="list-group-item"> <ul class="list-group"> <li class="list-group-item" ng-repeat="v in item.books track by $index" ng-init="innerIndex = $index"> {{v.name}} <span class="inner-index">innerIndex:{{innerIndex}}</span><button class="btn btn-danger" ng-click="vm.removeItem(outerIndex, innerIndex)">删除</button> </li> <li class="list-group-item"> <form class="form-inline"> <input class="form-control" ng-model="vm.tempItem[$index]" type="text"> <button class="btn btn-primary" ng-click="vm.addItem(outerIndex)">添加一项</button> </form> </li> </ul> </li> <hr ng-show="!$last"> </ul>
控制器部分:
function removeItem(outerIndex, innerIndex) { vm.appData[outerIndex].books.splice(innerIndex, 1); }
我们可以先看控制器里面的函数, removeItem
这个函数有两个参数,一个是 outerIndex
,一个是 innerIndex
,其中 outerIndex
表示的是第一层循环的 $index
索引, innerIndex
表示的是第二层的 $index
索引。每次删除一项我们都需要知道是删除第一层循环中哪一个对象中的哪一项。
在页面中我们通过 ng-init="outerIndex = $index"
保存了第一层循环的 $index
,通过使用 ng-init="innerIndex = $index"
保存了第二层循环的 $index
。所以接下来的操作都很方便了。
如果对我上面所说的还没有很好理解的话,你可以尝试自己练习一下。下面是源码部分:
HTML部分
<head> <meta charset="UTF-8"> <title>1</title> <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.css"> <link rel="stylesheet" href="../lib/jsonFormater/jsonFormater.css"> <script src="http://cdn.bootcss.com/jquery/2.0.0/jquery.js"></script> <script src="http://cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.js"></script> <script src="../lib/jsonFormater/jsonFormater.js"></script> <script src="../../angular-1.4.5/angular.js"></script> <script src="app.js"></script> <style> .outer-index { color: #FF0000; background-color: #f8f8f8; padding: 3px; border-radius: 6px; } .inner-index { color: #00AA00; background-color: #f8f8f8; padding: 3px; border-radius: 6px; } </style> </head> <body> <div class="container-fluid" ng-controller="AppController as vm"> <div class="row"> <div class="col-md-6"> <ul class="list-group" ng-repeat="item in vm.appData" ng-init="outerIndex = $index"> <h3>{{item.name}}<span class="outer-index">outerIndex:{{outerIndex}}</span></h3> <h4>{{item.author}}</h4> <li class="list-group-item"> <ul class="list-group"> <li class="list-group-item" ng-repeat="v in item.books track by $index" ng-init="innerIndex = $index"> {{v.name}} <span class="inner-index">innerIndex:{{innerIndex}}</span><button class="btn btn-danger" ng-click="vm.removeItem(outerIndex, innerIndex)">删除</button> </li> <li class="list-group-item"> <form class="form-inline"> <input class="form-control" ng-model="vm.tempItem[$index]" type="text"> <button class="btn btn-primary" ng-click="vm.addItem(outerIndex)">添加一项</button> </form> </li> </ul> </li> <hr ng-show="!$last"> </ul> </div> <div id="show-container" class="col-md-6"> <h3>vm.appData:</h3> <div id="json-container"></div> </div> </div> </div> </body>
JavaScript部分
(function() { angular.module('app', []) .controller('AppController', AppController); AppController.$inject = ['$scope']; function AppController($scope) { var vm = this; // 初始化原始数据 var appData = [ { name: 'C++从入门到放弃', author: 'dreamapple', books: [ {name: 'github'}, {name: 'google'}, {name: 'nodejs'}, {name: 'react'} ] }, { name: 'Java从入门到跑路', author: '呵呵哒', books: [ {name: '雪碧'}, {name: '百事可乐'}, {name: '鸡尾酒'} ] } ]; vm.appData = appData; vm.tempItem = []; vm.addItem = addItem; vm.removeItem = removeItem; config(); function addItem(outerIndex) { if(vm.tempItem[outerIndex]) { vm.appData[outerIndex].books.push({ name: vm.tempItem[outerIndex] }); vm.tempItem[outerIndex] = ''; vm.jf.doFormat(vm.appData); } else { alert('添加项不能为空!') } } function removeItem(outerIndex, innerIndex) { vm.appData[outerIndex].books.splice(innerIndex, 1); vm.jf.doFormat(vm.appData); } function config() { var options = { dom : '#json-container', tabSize: 2, quoteKeys: true, imgCollapsed: "../lib/jsonFormater/images/collapsed.gif", imgExpanded: "../lib/jsonFormater/images/expanded.gif", isCollapsible: true }; vm.jf = new JsonFormater(options); vm.jf.doFormat(vm.appData); } } })();