ng-repeat with recursive attributes object - angularjs

I'm currently learning angularjs 1.5.0
I'm making a small sample with a complex json object, like this :
{
"Families":[
{
"Name": "A",
"Age": 1,
"Children": [
{
"Name": "B",
"Age": 2,
"Children":[
{
"Name": "C",
"Age": 3
},
{
"Name": "D",
"Age": 4
}
]
}
]
},
{
"Name": "X",
"Age": 5,
"Children":[
{
"Name": "Y",
"Age": 2
},
{
"Name": "Z",
"Age": 4
}
]
}
]
}
As you see, Families contains many members, each member has name, age and children. I want to list out this family tree , but one thing is difficult to me is : I don't know how many children can a member have therefore I don't know how to list them out by using ng-repeat.
Can anyone help me please ?
Thank you so much,

For displaying recursive json data arrays, use recursive templates in views.
create a template like below
<script type="text/ng-template" id="familyTree">
{{ family .name}}
<ul ng-if="family.children">
<li ng-repeat="family in family.children" ng-include="'familyTree'">
</li>
</ul>
</script>
and use ng-repeat in view like this to render the view
<ul>
<li ng-repeat="family in families" ng-include="'familyTree'"></li>
</ul>
sample fiddle
more details

Related

What would be angular ng-option equivalent of this select?

I am struggling to get this into an ng-option. Is it even possible?
<select ng-model="detail_type_id">
<optgroup ng-repeat="type in data.detailTypes" label="{{type.name}}">
<option ng-repeat="t in type.children" value="{{t.id}}">{{t.name}}</option>
</optgroup>
</select>
DetailTypes looks like this:
[
{"id":7,
"parent_id":null,
"name":"Contact",
"children":[
{"id":8,
"parent_id":7,
"name":"Address",
"children":[]
},
{"id":12,
"parent_id":7,
"name":"Something else",
"children":[]
}
]},
{"id":16,
"parent_id":null,
"name":"Other",
"children":[
{"id":10,
"parent_id":16,
"name":"Remarks",
"children":[]}
]
}
]
Child id needs to be selected. Nesting cannot be deeper.
The ngOptions directive does not work with multidimensional objects. So you need to flatten your array to use it.
I wrote a filter for that:
app.filter('flatten' , function(){
return function(array){
return array.reduce(function(flatten, group){
group.children.forEach(function(child){
child.groupName = group.name;
flatten.push(child)
})
return flatten;
},[]);
}
})
And the HTML part would be like this:
<select ng-model="detail_type_id"
ng-options="item.id as item.name
group by item.groupName for item
in data.detailTypes | flatten track by item.id">
</select>
Plunker (version #1 with filter):
https://plnkr.co/edit/dxi7j8oxInv2VRJ1aL7F
I also modified your object to be like this:
[{
"id": 7,
"parent_id": null,
"name": "Contact",
"children": [{
"id": 8,
"parent_id": 7,
"name": "Address",
"children": []
}, {
"id": 12,
"parent_id": 7,
"name": "Something else",
"children": []
}]
}, {
"id": 16,
"parent_id": null,
"name": "Other",
"children": [{
"id": 10,
"parent_id": 16,
"name": "Remarks",
"children": []
}]
}]
EDIT:
After suggestion I wrote another version without the filter, but flattening the array inside the controller.
Additional Controller JS:
$scope.flattenDetailTypes = flattenDetailTypes($scope.data.detailTypes);
function flattenDetailTypes(array){
return array.reduce(function(flatten, group){
group.children.forEach(function(child){
child.groupName = group.name;
flatten.push(child)
})
return flatten;
},[]);
}
Markup:
<select ng-model="detail_type_id"
ng-options="item.id as item.name group by item.groupName for item in flattenDetailTypes track by item.id"></select>
Plunker (version #2 without filter):
https://plnkr.co/edit/D4APZ6

Using Angular Typeahead on Nested Objects

I'm trying to use Angular Bootstrap Typeahead on an array of nested objects and I cannot figure out how to write out the typeahead.
My objects in my array are like so:
{
"category": "Locations",
"regions": [
{
"name": "Northeast",
"category": "region",
"states": [
{
"name": "New York",
"category": "state"
"cities": [
{
"name": "Syracuse",
"category": "city"
}
]
}
]
}
I only want to return the name values. So how would I go about writing this out?
I currently am writing <input ... typeahead=" filter.name for filter in filters| filter:$viewValue | limitTo:5">
Rather than using "in filters" just do something like "in transformFilters()"
$scope.transformFilters = function () {
// Loop over filters and create an array of
{name: name, category:cat}
return my new array
}

AngularJs orderBy filter not working with tracking

I am at a lost on why orderBy is not working, the order of ng-repeat output is the same no matter what property I pass to orderBy e.g orderBy:'-year1comp' or orderBy:'year1comp' has no effect.
$scope.expTest = [{
"company": "new",
"schedule": "fulltime",
"titlecomp": "c",
"status": "temporary",
"locationcomp": "fdsf",
"category": "114",
"month1comp": 4,
"year1comp": 2004,
"month2comp": 5,
"year2comp": 1997,
"desccomp": "dafds",
"companydesc": "fdsaf",
"_id": 0
}, {
"company": "new",
"schedule": "fulltime",
"titlecomp": "b",
"status": "temporary",
"locationcomp": "fdsf",
"category": "114",
"month1comp": 4,
"year1comp": 2015,
"month2comp": 2,
"year2comp": 2010,
"desccomp": "dafds",
"companydesc": "fdsaf",
"_id": 1
}, {
"company": "company name",
"schedule": "fulltime",
"titlecomp": "a",
"status": "contract",
"locationcomp": "sfdg",
"category": "114",
"month1comp": 2,
"year1comp": 2015,
"desccomp": "fdgsfdg",
"companydesc": "fdgfdg",
"_id":2
}]
template HTML
<div class="multiple-repeat-container"
ng-repeat="item in expTest track by $index | orderBy:'-year1comp' "> ... </div>
You need to move tracking after the orderBy:
<div class="multiple-repeat-container" ng-repeat="item in expTest | orderBy:'-year1comp' track by $index "> ... </div>
The documentation states
Note that the tracking expression must come last, after any filters, and the alias expression.

Angular properties (variables) use in the view

I have a list of schools and a list of teachers.
Schools
[
{
"id": 1,
"nameOfInstitution": "Summer Elementary",
"schoolLevel": "01304"
},
{
"id": 2,
"nameOfInstitution": "Grady Middle",
"schoolLevel": "02400"
}
]
Teachers
[
{
"id": "1",
"school": "1",
"name": {
"lastOrSurname": "HARRISON",
"firstName": "JOHN",
"middleName": ""
}
},
{
"id": "2",
"school": "1",
"name": {
"lastOrSurname": "Nelson",
"firstName": "Darren",
"middleName": ""
}
},
{
"id": "3",
"school": "2",
"name": {
"lastOrSurname": "Stewart",
"firstName": "Manuel",
"middleName": ""
}
}]
In the controller I have
...
$scope.schools = schools;
$scope.teachers = teachers;
The question is related to the view. How can I achieve this?
Summer Elementary
JOHN HARRISON
Darren Nelson
Grady Middle
Manuel Steward
I've been using the "ng-repeat" directive, but how can I display only the teachers that belong to each schools?
Thanks!
You can filter the teachers in your ng-repeat:
<div ng-repeat="school in schools">
<div ng-repeat="teacher in teachers | filter: {school: school.id}">
But be sure to add an id property for each school that are used by the teachers.
Or if the teacher.school properties are the schools index in the schools array, you can do that:
<div ng-repeat="school in schools">
<div ng-repeat="teacher in teachers | filter: {school: $index}">
A final note: this will work but if you have many schools and teacher, it would be more performant to perform the filtering from javascript before you display it, i.e. build a structure like
schools = [{
nameOfInstitution: ...,
schoolLevel: ...,
teachers: [{
lastOrSurname: ...
}]
// ... etc
}];
Use filter:
<div ng-repeat="school in schools">
{{school.nameOfInstitution}}
<p ng-repeat="teacher in teachers | filter:{school: ''+ ($index+1)}:true">
{{teacher.name.lastOrSurname}}
</p>
</div>
But you'd better have some sort of id for schools...

object nested into a nested array, how to implement a custom filter for it?

I have an application that I am constructing with a friend and we have a very big problem: I have a very big json with some nested arrays an objects, I am using a filter with an ng-model="search" the filter (search) works great with the top level array which is named sports, but once I try to search through the leagues array, the filter returns nothing. I saw in another question that I can search(filter) based on nested properties which is exactly what I want. I tried to follow the example answer on that question but I am having a problem trying to solve this. Someone else says: that is not possible with this kind of matching that you are trying because you want to filter through a matching sport.name and all of his matching and not non matching leagues or a non matching sport.name and only his matching leagues.
json
[
{
"name": "Cricket",
"leagues": []
},
{
"name": "NBA Games",
"leagues": [
{
"name": "NBA",
"sport": {
"id": 8,
"name": "NBA Earliest"
},
"lineType": "G",
"priority": [
1,
3
],
"part": "0"
}
]
},
{
"name": "COLLEGE Basketball",
"leagues": [
{
"name": "College - NCAA BASKETBALL",
"sport": {
"id": 24,
"name": "College Basketball"
},
"lineType": "G",
"priority": [
0,
4
],
"part": "0"
},
{
"name": "NCAA BASKETBALL ADDED GAMES",
"sport": {
"id": 24,
"name": "College Basketball"
},
"lineType": "G",
"priority": [
1,
4
],
"part": "0"
},
...
my html
<input type="search" ng-model="search">
<div ng-repeat="sport in sports | filter: query">
<!-- searching (filtering) great -->
<div>{{sport.name}}</div>
</div>
<div ng-repeat="league in sport.leagues | filter: query">
<!-- here is not filtering at all -->
{{league.name}}
</div>
</div>
can I do it this way I am trying or how do I implement a custom filter for this ?

Resources