In my app I have an array of objects with the following structure
[{"ID":1, "parentID":0, "name":"Parent #1"},
{"ID":2, "parentID":0, "name":"Parent #2"},
{"ID":3, "parentID":1, "name":"Child #1 1"},
{"ID":4, "parentID":3, "name":"child #1 2"},
{"ID":5, "parentID":2, "name":"child #2 1"},
{"ID":6, "parentID":5, "name":"child #2 2"}]
I'd like to present this as a select menu which would allow a user to select a leaf node while still outputting non-selectable parent nodes to display the hierarchy of the structure.
I've tried a few approaches, the most successful of which was, in my angular template, something along the lines of the following.
<div ng-repeat="(idx, category) in $scope.allCats">
<select ng-model="$scope.cats[idx]"
ng-options="cat as cat.name group by $scope.parentName(cat.parentID, idx) for cat in $scope.allCategories track by cat.ID">
<option value="">Select A Category</option>
</select>
</div>
$scope.allCats
is the array above and $scope.parentName()
method returns a string.
The troubles with this are demonstrated in the following screenshot. Namely all parent items appear twice, once as an <option>
and once as an <optgroup>
, whereas I'd rather they only appeared as a selectable item but with them being obviously a parent item, and the hierarchy of the structure is not maintained; child nodes with ancestors and descendants do not appear in the correct 'family-tree' structure.
How can I alter my injected data or my angular template to achieve the behaviour I desire?
That is, to display the entire hierarchy, as defined by the parentID
attributes so each family shares a common ancestor, and with parent items only appearing once.
I suspect this is being complicated by the fact there is more than one level of descendants possible and because I would like to keep this as general as possible.
What about sorting the array in the scope before passing it to the angular template?. If you have:
var arr = [
{"ID":1, "parentID":0, "name":"Parent #1"},
{"ID":3, "parentID":1, "name":"Child #1 1"},
{"ID":4, "parentID":3, "name":"child #1 2"},
{"ID":7, "parentID":4, "name":"asdfadsf"},
{"ID":2, "parentID":0, "name":"Parent #2"},
{"ID":5, "parentID":2, "name":"child #2 1"},
{"ID":6, "parentID":5, "name":"child #2 2"}
];
it would be easier. Just show it as it is.
var sortKeys = {};
// computes a unique sort key
function getSortKey(item) {
if(sortKeys[item.ID] === undefined) {
var parentItem = arr.filter(function(it) {
return it.ID === item.parentID;
})[0];
if(parentItem != null) {
return getSortKey(parentItem) + '' + item.ID;
}
return item.parentID + '' + item.ID;
}
return sortKeys[item.ID];
}
// build sort keys to be used to sort items following their hierarchy
arr.forEach(function(item) {
sortKeys[item.ID] = getSortKey(item);
});
// sort the array
arr.sort(function(item1, item2) {
var item1SortKey = sortKeys[item1.ID],
item2SortKey = sortKeys[item2.ID];
return item1SortKey < item2SortKey ?
-1 :
(item1SortKey > item2SortKey ?
1:
0);
});
var arr = [{"ID":1, "parentID":0, "name":"Parent #1"},
{"ID":2, "parentID":0, "name":"Parent #2"},
{"ID":3, "parentID":1, "name":"Child #1 1"},
{"ID":4, "parentID":3, "name":"child #1 2"},
{"ID":5, "parentID":2, "name":"child #2 1"},
{"ID":6, "parentID":5, "name":"child #2 2"},
{"ID":7, "parentID":4, "name":"asdfadsf"}];
var sortKeys = {};
// computes a unique sort key
function getSortKey(item) {
if(sortKeys[item.ID] === undefined) {
var parentItem = arr.filter(function(it) {
return it.ID === item.parentID;
})[0];
if(parentItem != null) {
return getSortKey(parentItem) + '' + item.ID;
}
return item.parentID + '' + item.ID;
}
return sortKeys[item.ID];
}
// build sort keys to be used to sort items following their hierarchy
arr.forEach(function(item) {
sortKeys[item.ID] = getSortKey(item);
});
// sort the array
arr.sort(function(item1, item2) {
var item1SortKey = sortKeys[item1.ID],
item2SortKey = sortKeys[item2.ID];
return item1SortKey < item2SortKey ?
-1 :
(item1SortKey > item2SortKey ?
1:
0);
});
document.getElementById('result').innerHTML = JSON.stringify(arr, null, 2);
<pre id="result"></pre>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With