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?