如何在Angular 6中过滤复杂的结构化Json数据

Les*_*ter 5 json typescript angular

我有一个复杂的结构化json数据,需要在我的Angular 6 App中应用高级过滤.

JSON数据:

[{
    "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个下拉列表来过滤:

  1. 性别
  2. ProgramCategory
  3. ProgramStatus

HTML视图:

UI视图如下所示: 在此输入图像描述

通缉结果:

当我选择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)

我的HTML代码:

<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代码或有一个新的解决方案,欢迎两者!

非常感谢!

Zac*_*ose 3

我在这里使用反应式表单和 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 为中心的方法。