I have a complex structured json data that needs to be apply an advanced filtering in my Angular 6 App.
JSON Data:
[{
"StudentId": 1,
"StudentName": "Student1",
"Sex":"M",
"Programs": [
{
"StudentId": 1,
"ProgramName": "Java",
"ProgramCategory": "Engineering",
"ProgramStatus": "Full Time"
},
{
"StudentId": 1,
"ProgramName": "HR Management 2",
"ProgramCategory": "HR",
"ProgramStatus": "Part Time"
},
{
"StudentId": 1,
"ProgramName": "Accounting 1",
"ProgramCategory": "Finance",
"ProgramStatus": "Full Time"
}
]
},
{
"StudentId": 2,
"StudentName": "Student2",
"Sex":"F",
"Programs": [
{
"StudentId": 2,
"ProgramName": "HR Management 1",
"ProgramCategory": "HR",
"ProgramStatus": "Part Time"
},
{
"StudentId": 2,
"ProgramName": "Accounting 3",
"ProgramCategory": "Finance",
"ProgramStatus": "Full Time"
}
]
},
{
"StudentId": 3,
"StudentName": "Student3",
"Sex":"F",
"Programs": [
{
"StudentId": 3,
"ProgramName": "Java 3",
"ProgramCategory": "Engineering",
"ProgramStatus": "Full Time"
}
]
},
{
"StudentId": 4,
"StudentName": "Student4",
"Sex":"M",
"Programs": [
{
"StudentId": 4,
"ProgramName": "Java 2",
"ProgramCategory": "Engineering",
"ProgramStatus": "Full Time"
},
{
"StudentId": 4,
"ProgramName": "Accounting 2",
"ProgramCategory": "Finance",
"ProgramStatus": "Part Time"
}
]
},
{
"StudentId": 5,
"StudentName": "Student5",
"Sex":"M",
"Programs": [
{
"StudentId": 5,
"ProgramName": "JavaScript",
"ProgramCategory": "Engineering",
"ProgramStatus": "Part Time"
},
{
"StudentId": 5,
"ProgramName": "HR Management 5",
"ProgramCategory": "HR",
"ProgramStatus": "Full Time"
}
]
}]
Filter Options:
I would like to have 3 drop-down list in HTML page to filter by:
- Sex
- ProgramCategory
- ProgramStatus
HTML View:
The UI View will look like the below:
Wanted Result:
When I select ProgramCategory = 'HR'
and ProgramStatus = 'Part Time'
, there will be only 2 students (student1
,student2
) returned. I spend days try to get the result that I want, but still not solve. I use this article as ref and made some improvement based on my data, but the returned data is incorrect, see the image below:
So, I only need the marked rows (
row#:1,2
) to be returned.
The the marked row#:5 is marked by mistake in the image above.
My ts code:
import { Component, OnInit } from '@angular/core';
import * as _ from 'lodash';
@Component({
selector: 'app-hfo',
templateUrl: './hfo.component.html',
styleUrls: ['./hfo.component.css']
})
export class HfoComponent implements OnInit {
students: any;
filteredStudents: any;
// basic info
Sex: string;
// child info
ProgramCategory: string;
ProgramStatus: string;
// filter by value
filters = { };
constructor() { }
ngOnInit() {
/// get all students
this.students = this.getStudents();
this.setFilters();
}
private setFilters() {
this.filteredStudents = _.filter(this.students, _.conforms(this.filters) );
}
filterMatch(property: string, value: any) {
this.filters[property] = i => i === value;
this.setFilters();
}
filterMatchSub(property: string, childProperty: string, value: any) {
this.filters[property] = val => val.find( child => child[childProperty] === value);
this.setFilters();
}
/// removes filter
removeFilter(property: string) {
delete this.filters[property];
this[property] = null;
this.ProgramCategory = null;
this.ProgramStatus = null;
this.setFilters();
}
private getStudents() {
return JSON.parse(`
[
{
"StudentId": 1,
"StudentName": "Student1",
"Sex":"M",
"Programs": [
{
"StudentId": 1,
"ProgramName": "Java",
"ProgramCategory": "Engineering",
"ProgramStatus": "Full Time"
},
{
"StudentId": 1,
"ProgramName": "HR Management 2",
"ProgramCategory": "HR",
"ProgramStatus": "Part Time"
},
{
"StudentId": 1,
"ProgramName": "Accounting 1",
"ProgramCategory": "Finance",
"ProgramStatus": "Full Time"
}
]
},
{
"StudentId": 2,
"StudentName": "Student2",
"Sex":"F",
"Programs": [
{
"StudentId": 2,
"ProgramName": "HR Management 1",
"ProgramCategory": "HR",
"ProgramStatus": "Part Time"
},
{
"StudentId": 2,
"ProgramName": "Accounting 3",
"ProgramCategory": "Finance",
"ProgramStatus": "Full Time"
}
]
},
{
"StudentId": 3,
"StudentName": "Student3",
"Sex":"F",
"Programs": [
{
"StudentId": 3,
"ProgramName": "Java 3",
"ProgramCategory": "Engineering",
"ProgramStatus": "Full Time"
}
]
},
{
"StudentId": 4,
"StudentName": "Student4",
"Sex":"M",
"Programs": [
{
"StudentId": 4,
"ProgramName": "Java 2",
"ProgramCategory": "Engineering",
"ProgramStatus": "Full Time"
},
{
"StudentId": 4,
"ProgramName": "Accounting 2",
"ProgramCategory": "Finance",
"ProgramStatus": "Part Time"
}
]
},
{
"StudentId": 5,
"StudentName": "Student5",
"Sex":"M",
"Programs": [
{
"StudentId": 5,
"ProgramName": "JavaScript",
"ProgramCategory": "Engineering",
"ProgramStatus": "Part Time"
},
{
"StudentId": 5,
"ProgramName": "HR Management 5",
"ProgramCategory": "HR",
"ProgramStatus": "Full Time"
}
]
}
]
`);
}
}
My HTML Code:
<div class="row">
<div class="col-sm-12">
<div class="panel panel-sm ">
<div class="panel-body">
<h5>Basic Info</h5>
<div class="hs-lead">
<div class="row">
<div class="col-sm-3">
<div class="form-group">
<label for="exampleSelect1">Sex</label>
<div class="row">
<div class="col-sm-9">
<select class="form-control" [(ngModel)]="Sex" (change)="filterMatch('Sex', Sex)">
<option value="M">M</option>
<option value="F">F</option>
</select>
</div>
<div class="col-sm-3">
<button class="btn btn-primary" *ngIf="Sex" (click)="removeFilter('Sex')">
Clear
</button>
</div>
</div>
</div>
</div>
<div class="col-sm-3">
<div class="form-group">
<label for="exampleSelect1">ProgramCategory</label>
<div class="row">
<div class="col-sm-9">
<select class="form-control" [(ngModel)]="ProgramCategory" (change)="filterMatchSub('Programs', 'ProgramCategory', ProgramCategory)">
<option value="Engineering">Engineering</option>
<option value="HR">HR</option>
<option value="Finance">Finance</option>
</select>
</div>
<div class="col-sm-3">
<button class="btn btn-primary" *ngIf="ProgramCategory" (click)="removeFilter('Programs')">
Clear
</button>
</div>
</div>
</div>
</div>
<div class="col-sm-3">
<div class="form-group">
<label for="exampleSelect1">ProgramStatus</label>
<div class="row">
<div class="col-sm-9">
<select class="form-control" [(ngModel)]="ProgramStatus" (change)="filterMatchSub('Programs', 'ProgramStatus', ProgramStatus)">
<option value="Full Time">Full Time</option>
<option value="Part Time">Part Time</option>
</select>
</div>
<div class="col-sm-3">
<button class="btn btn-primary" *ngIf="ProgramStatus" (click)="removeFilter('Programs')">
Clear
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="panel panel-xl">
<div class="panel-body">
<h5>Result
<span class="badge badge-info badge-pill pull-right">{{ filteredStudents.length }}</span>
</h5>
<div class="hs-lead">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Sex</th>
<th>Programs</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let item of filteredStudents ">
<td>{{item.StudentId }}</td>
<td>{{item.StudentName }}</td>
<td>{{item.Sex}}</td>
<td>
{{item.Programs.length}}
<ol *ngFor="let obj of item.Programs">
<li>{{obj.ProgramCategory}} / {{obj.ProgramStatus}}</li>
</ol>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
Help:
Could anyone help me to achieve my goal?
You can change my current ts code or have a new solution, both are welcomed!
Thanks a lot!