AngularJS:遍历嵌套数组 [英] AngularJS: traversing nested arrays

查看:40
本文介绍了AngularJS:遍历嵌套数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用具有结构的嵌套数组...

$scope.items = [{attr1: val1,属性2:val2,项目: [{属性 1: val1,属性2:val2,项目: [{...}, ...]}, ...]}, ...];

它进入一个 ng-repeatng-include 像这样

<div ng-repeat="item in items" ng-include="'/path/to/template.tpl.html'"></div>

template.tpl.html

{{item.attr1}}<\div><div>{{item.attr2}}<\div><div ng-click="fnAddNewItemBelow(item, $parent)"><\div><div ng-repeat="item.items 中的项目" ng-include="'/path/to/template.tpl.html'"><\div>

现在,在控制器中,我通常想做类似

  • 查找项目的父项
  • 找到一个项目的兄弟
  • 计算兄弟姐妹的数量
  • 找出一个项目嵌套了多少层
  • 在嵌套的任何级别插入或删除项目

但我不确定如何优雅地做到这一点.例如,假设我想实现 fnAddNewItemBelow.我可以解决的两个选项是

遍历范围

使用 Angular 提供的嵌套作用域结构

//仅伪代码$scope.fnAddNewItemBelow = 函数(项目,父项){var newItem = ...;//在被 ng 单击的项之后添加 newItem 作为兄弟项//parent.$parent 是必要的,因为 ng-include 添加了另一个作用域层(我认为)parent.$parent.item.items.push(newItem);//(可能需要使用.splice,以防item后面有item,//但我保持简单)}

但这很丑陋,因为它对结构假设太多(如果我将 ng-if 放在 <div ng-click... 上会怎样,这增加了另一个范围级别... 那么我需要 parent.$parent.$parent.item.items.push(newItem)).

递归迭代嵌套数组,直到找到 item.id

另一种方法是直接对 $scope.items 进行操作,因为 Angular 将更新与其关联的 UI 和范围.我可以使用 for 循环通过 $scope.items 递归迭代,并在通过它拥有的某个唯一 id 定位 item 后,在它之后插入 newItem

//仅伪代码$scope.fnAddNewItemBelow = 函数(项目){var newItem = ...;//在被 ng 单击的项之后添加 newItem 作为兄弟项fnSomeFunctionToFindItemAndInsertItemAfterIt(item.id, newItem);}fnSomeFunctionToFindItemAndInsertItemAfterIt (itemId, newItem) {//花哨的递归函数,for 循环遍历每个项目,并调用//当有子项时本身.当它找到带有 itemId 的项目时,它//拼接在newItem之后}

我不喜欢这样,因为每次我想对嵌套数组做某事时,它都需要遍历整个项目树.

有更优雅的解决方案吗?

解决方案

如果你在 ng-repeat 表达式中给 item.items 加上别名,angular 将跟踪数组结构和层次关系.

然后,树上的操作可以简单地传入 item$indexitems 数组 - 无需知道完整的数组结构:

 <button ng-click="addItem(item)">添加到我的项目</button><button ng-click="addSiblingItem(items, $index)">添加同级项</button><button ng-click="deleteMe(items, $index)">删除我</button>

js:

$scope.addItem = function(item) {item.items.push({attr1: '我的新 - attr1',attr2: '我的新 - attr2',项目: []});}$scope.addSiblingItem = function(items, position) {items.splice(位置 + 1, 0, {attr1: '兄弟姐妹 - 新的 attr1',attr2: '兄弟姐妹 - 新的 attr2',项目: []});}$scope.deleteMe = 函数(项目,位置){items.splice(位置, 1);}

获取兄弟数量可以参考items.length:

Item #{{$index + 1}} of {{items.length}}

<小时>

如果您确实需要从子项访问父兄弟项,您可以为 parent = item 添加另一个别名,并使用 ng-init 将其添加到项中:

ng-repeat="item in items = (parent = item).items" ng-init="item.parent = parent"

然后您就可以访问祖父母(parent.parent)及其items(父兄弟姐妹).

此外,您可以使用 ng-init 跟踪当前嵌套级别:

ng-init="item.parent = parent; item.level = parent.level + 1"

这是一个工作演示:http://plnkr.co/xKSwHAUdXcGZcwHTDmiv

I am working with a nested array with the structure...

$scope.items = [{attr1: val1, 
  attr2: val2,
  items: [{
     attr1: val1, 
     attr2: val2,
     items: [{
     ... 
     }, ...]
  }, ...]
}, ...];

which goes into an ng-repeat with ng-include like this

<div ng-repeat="item in items" ng-include="'/path/to/template.tpl.html'"></div>

and template.tpl.html is

<div>{{item.attr1}}<\div>
<div>{{item.attr2}}<\div>
<div ng-click="fnAddNewItemBelow(item, $parent)"><\div>
<div ng-repeat="item in item.items" ng-include="'/path/to/template.tpl.html'"><\div>

Now, in the controller, I commonly want to do things like

  • find an item's parent
  • find an item's sibling
  • make counts of siblings
  • find out how many levels deep an item is nested
  • insert or delete items at any level of the nest

But I'm not sure how to do this elegantly. Eg imagine I wanted to implement fnAddNewItemBelow. The two options I can work out are

Traverse scopes

Use the nested scopes structure that Angular provides

// pseudo-code only
$scope.fnAddNewItemBelow = function (item, parent) {
  var newItem = ...;

  // add newItem as a sibling after the item that was ng-clicked
  // parent.$parent is necessary because the ng-include adds another scope layer (I think)
  parent.$parent.item.items.push(newItem);

  // (probably need to use .splice in case there are items after item, 
  //  but I'm keeping it simple)
}

But this is ugly because it assumes too much about the structure (what if I put an ng-if onto the <div ng-click..., which added another scope level... then I'd need parent.$parent.$parent.item.items.push(newItem)).

Iterate nested array recursively until item.id is found

The alternative is to operate directly on $scope.items, since Angular will update UI and scopes associated with it. I can iterate recursively through $scope.items using for loops and after locating item by some unique id that it has, insert newItem after it

// pseudo-code only
$scope.fnAddNewItemBelow = function (item) {
  var newItem = ...;

  // add newItem as a sibling after the item that was ng-clicked
  fnSomeFunctionToFindItemAndInsertItemAfterIt(item.id, newItem);
}

fnSomeFunctionToFindItemAndInsertItemAfterIt (itemId, newItem) {
  // fancy recursive function that for loops through each item, and calls 
  // itself when there are children items. When it finds item with itemId, it 
  // splices in the newItem after
}

I don't like this because it requires iterating through the entire items tree every time I want to do something with the nested array.

Are there more elegant solutions?

解决方案

If you alias item.items in the ng-repeat expression, angular will keep track of the array structure and hierarchical relationships for you.

<div ng-repeat="item in items = item.items">

Then, operations on the tree can simply pass in the item, the $index, or the array of items - without knowledge of the full array structure:

  <button ng-click="addItem(item)">Add to my items</button>
  <button ng-click="addSiblingItem(items, $index)">Add a sibling item</button>
  <button ng-click="deleteMe(items, $index)">Delete Me</button>

js:

$scope.addItem = function(item) {
  item.items.push({
    attr1: 'my new - attr1',
    attr2: 'my new - attr2',
    items: []
  });
}
$scope.addSiblingItem = function(items, position) {
  items.splice(position + 1, 0, {
    attr1: 'sibling - new attr1',
    attr2: 'sibling - new attr2',
    items: []
  });
}
$scope.deleteMe = function(items, position) {
  items.splice(position, 1);
}

To get the number of siblings, you can refer to items.length:

<h3>Item #{{$index + 1}} of {{items.length}}</h3>


If you really need to access the parent siblings from child items, you can add another alias for parent = item and add it to the item using ng-init:

ng-repeat="item in items = (parent = item).items" ng-init="item.parent = parent"

Then you have access to the grandparent (parent.parent) and its items (the parent siblings).

In addition, you can keep track of the current nest level using ng-init:

ng-init="item.parent = parent; item.level = parent.level + 1"

Here is a working demo: http://plnkr.co/xKSwHAUdXcGZcwHTDmiv

这篇关于AngularJS:遍历嵌套数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆