Les*_*ter 5 json typescript angular
我有一个复杂的结构化json数据,需要在我的Angular 6 App中应用高级过滤.
[{
"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"
}
]
}]
Run Code Online (Sandbox Code Playgroud)
我想在HTML页面中有3个下拉列表来过滤:
当我选择ProgramCategory = 'HR'
并且ProgramStatus = 'Part Time'
,将只返回2个学生(student1
,student2
).我花了几天时间试着得到我想要的结果,但仍然没有解决.我使用这篇文章作为参考,并根据我的数据做了一些改进,但返回的数据不正确,请参见下图:
所以,我只需要
row#:1,2
返回标记的行().
标记的行#:5在上图中被错误标记.
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"
}
]
}
]
`);
}
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)
谁能帮助我实现目标?
您可以更改我当前的ts代码或有一个新的解决方案,欢迎两者!
非常感谢!
我在这里使用反应式表单和 rxjs BehaviourSubjects 为您提供了一个解决方案:
https://stackblitz.com/edit/how-to-filter-complex-json-data-new-chind-array-object-xtlbxy
该链接有您的完整解决方案,但这是我认为您遇到的过滤问题的核心:
private setFilters() {
this.filteredStudents$.next(this.students$.value);
combineLatest(
this.students$,
this.sexFilterControl.valueChanges,
this.programControls.valueChanges,
this.courseControls.valueChanges
)
.subscribe(([students, sexFilter, programFilters, courseFilters]) => {
let filteredStudents = [ ... students ];
if (sexFilter) {
filteredStudents = filteredStudents.filter(student => student.Sex === sexFilter);
}
// programs
filteredStudents = filteredStudents.filter(student => {
return student.Programs.reduce((programsPrev, program) => {
return programsPrev || Object.entries(programFilters).reduce((filterPrev, [filterName, filterValue]) => {
if (!filterValue) {
return filterPrev;
}
return filterPrev && program[filterName] === filterValue;
}, true);
}, false)
});
// courses
filteredStudents = filteredStudents.filter(student => {
return student.Courses.reduce((coursesPrev, course) => {
return coursesPrev || Object.entries(courseFilters).reduce((filterPrev, [filterName, filterValue]) => {
if (!filterValue) {
return filterPrev;
}
return filterPrev && course[filterName] === filterValue;
}, true);
}, false)
});
this.filteredStudents$.next(filteredStudents);
});
this.sexFilterControl.setValue('');
this.programCategoryFilterControl.setValue('');
this.programStatusFilterControl.setValue('');
this.courseCategoryFilterControl.setValue('');
this.courseStatusFilterControl.setValue('');
}
Run Code Online (Sandbox Code Playgroud)
对 ProgramCategory 和 ProgramStatus 进行过滤(两者必须与同一个程序匹配)与分别进行过滤是完全不同的过滤器。
由于您对两个程序过滤器的需求本质上是“仅显示至少有 1 个与所有现有过滤器匹配的程序的学生”,因此您可以在我的堆栈闪电战中看到我将相关控件分组到 a 中FormGroup
并编写反映此的过滤器预期行为。
如果您愿意,我建议将您的表格调整为使用@angular/cdk/table
,我实际上正在与 Angular Firebase 的人一起撰写一篇关于该主题的文章(如您发布的链接中所示)。我认为这是非常值得的,特别是如果您喜欢我在这个解决方案中使用的这种更以 rxjs 为中心的方法。
归档时间: |
|
查看次数: |
2604 次 |
最近记录: |