web-dev-qa-db-fra.com

Comment filtrer des données Json complexes et structurées dans Angular 6

J'ai des données json structurées complexes qui doivent être appliquées à un filtrage avancé dans mon Angular 6 App. 

Données 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"
        }
    ]
 }]

Options de filtrage:

Je voudrais avoir 3 liste déroulante dans la page HTML pour filtrer par:

  1. Sexe
  2. ProgrammeCatégorie
  3. État du programme

Vue HTML:

La vue de l'interface utilisateur ressemblera à celle ci-dessous:  enter image description here

Résultat recherché:

Lorsque je sélectionne ProgramCategory = 'HR' et ProgramStatus = 'Part Time', il n'y aura que 2 étudiants (student1, student2) retournés. Je passe des jours à essayer d’obtenir le résultat que je veux, mais toujours pas à résoudre. J'utilise cet article comme référence et j'apporte des améliorations en fonction de mes données, mais les données renvoyées sont incorrectes, voir l'image ci-dessous:  enter image description here Je n'ai donc besoin que des lignes marquées (row#:1,2) pour être renvoyées.

La rangée #: 5 est marquée par erreur dans l'image ci-dessus.

Mon code de ts:

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"
              }
          ]
       }
  ]
    `);
  }

}

Mon code 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>

Aidez-moi:

Quelqu'un pourrait-il m'aider à atteindre mon objectif?

Vous pouvez changer mon code ts actuel ou avoir une nouvelle solution, les deux sont les bienvenus!

Merci beaucoup! 

5
Lester

J'ai une solution pour vous ici en utilisant des formes réactives et des objets BehaviorSubjects de rxjs:

https://stackblitz.com/edit/how-to-filter-complex-json-data-new-chind-array-object-xtlbxy

Ce lien a votre solution complète, mais voici l'essentiel du problème du filtrage, je pense que vous aviez:

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('');
}

Filtrer à la fois pour ProgramCategory et ProgramStatus (où les deux doivent correspondre pour le même programme) est un filtre fondamentalement différent du filtrage séparé.

Comme vous voulez ce que vous voulez avec vos deux filtres de programme est essentiellement de "montrer uniquement aux étudiants qui ont au moins un programme qui correspond à tous les filtres existants", vous pouvez voir dans mon blitz de pile que je regroupe les contrôles pertinents dans une FormGroup et écrit des filtres qui reflètent ce comportement prévu.

Si vous le souhaitez, je vous recommande d’ajuster votre tableau à l’utilisation de @angular/cdk/table , je travaille actuellement sur un article sur ce sujet avec le type de Angular Firebase (comme dans le lien que vous avez posté). Je pense que cela en vaudrait la peine, surtout si vous aimez cette approche plus centrée sur les risques que j'ai utilisée dans cette solution.

3
ZackDeRose

Définissez vos filtres, puis appelez la méthode suivante avec les valeurs appropriées.

const people = [{
  "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"
    }
  ]
}];

const findFilteredStudents = (students, sex, category, status) => {
  const foundStudents = students.filter(student => {
    // if sex is set as a filter, compare students to it
    if (sex && student.sex !== sex) {
      return false;
    }

    // if category is a filter, return false if a student
    // does not have the category
    if (category) {
      const hasCategory = student.Programs.find(Program => Program.ProgramCategory === category);
      if (!hasCategory) {
        return false;
      }
    }

    // if status is a filter, return false if a student
    // does not have the status
    if (status) {
      const hasStatus = student.Programs.find(Program => Program.ProgramStatus === status);
      if (!hasStatus) {
        return false;
      }
    }

    return true;
  });

  return foundStudents;
};

const students = findFilteredStudents(people, null, 'HR', 'Part Time');

students.forEach(student => {
  console.log(student);
})

1
VtoCorleone

Étant donné que la clé de this.filters [propriété] est toujours Programmes, vous écrasez toujours la sélection précédente. Pour cette raison, seul le dernier des 2 sous-filtres est appliqué.

Au lieu de cela, vous devriez vérifier si un filtre est déjà défini pour this.filters[property]. Si c'est le cas, assurez-vous qu'il est également coché.

Vous pouvez modifier votre filterMatchSub comme ceci:

 filterMatchSub(property: string, childProperty: string, value: any) {
    let existing = (val) => true; // Define a function that always returns true
    // If a filter is already defined, hold a reference to it in existing
    if (this.filters[property]) {
      existing = this.filters[property];
    }

    // Call the existing function as well
    this.filters[property] = val => val.find( child => child[childProperty]  === value) && existing(val);
    this.setFilters();
  }

Voici une démo de Stackblitz

1
user184994

Voici mon point de vue complet sur la façon dont cela devrait être géré. Exemple de travail complet sur stackblitz .

Module:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

import { AppComponent } from './app.component';

@NgModule({
  imports: [BrowserModule, FormsModule, ReactiveFormsModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule { }

Composant:

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { STUDENTS } from './students';

interface FilterFormValue {
  sex: string;
  category: string;
  status: string;
}

interface Program {
  studentId: number;
  programName: string;
  programCategory: string;
  programStatus: string;
}

export interface Student {
  studentId: number;
  studentName: string;
  sex: string;
  programs: Array<Program>;
}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {

  students: Array<Student> = [];
  filteredStudents: Array<Student> = [];

  sexOptions: Array<string> = [];
  programCategoryOptions: Array<string> = [];
  programStatusOptions: Array<string> = [];

  filterForm: FormGroup;

  constructor(private formBuilder: FormBuilder) { }

  ngOnInit() {
    this.getStudents();
  }

  private getStudents() {
    // you would get students from an API in a real Word scenario, now we just simply initialize it here
    // I put the data in a different file for convinience
    this.students = STUDENTS;
    // also setting filtered students to all of the students to display all of them at the start
    this.filteredStudents = this.students;
    // again, normally you would get these options from the backend but here we simply reduce our array of students
    this.getSexOptions();
    this.getProgramCategoryOptions();
    this.getProgramStatusOptions();
    // when we get all our data initialize the filter form
    this.initFilterForm();
  }

  private getSexOptions() {
    // get all unique values from array of students
    this.sexOptions = Array.from(new Set(this.students.map((student: Student) => student.sex)));
  }

  private getProgramCategoryOptions() {
    // this is a little bit trickier and normally you get these from the backend
    // but suffice it to say that at the end we get all unique values for program categories
    const categoryGroups = this.students.map((student: Student) => {
      return student.programs.map((program: Program) => program.programCategory);
    });
    this.programCategoryOptions = Array.from(new Set(categoryGroups.reduce((a, b) => a.concat(b))));
  }

  private getProgramStatusOptions() {
    // same as categories, we get all unique values for program statuses
    const statusGroups = this.students.map((student: Student) => {
      return student.programs.map((program: Program) => program.programStatus);
    });
    this.programStatusOptions = Array.from(new Set(statusGroups.reduce((a, b) => a.concat(b))));
  }

  private initFilterForm() {
    // initialize the form with empty strings, in html the 'All' option will be selected
    this.filterForm = this.formBuilder.group({
      sex: [''],
      category: [''],
      status: ['']
    });
    // init watch for any form changes
    this.watchFormChanges();
  }

  private watchFormChanges() {
    // this will fire on any filter changes and call the filtering method with the value of the form
    this.filterForm.valueChanges.subscribe((value: FilterFormValue) => this.filterStudents(value));
  }

  private filterStudents(value: FilterFormValue) {
    // again, this operation would be executed on the backend, but here you go
    // initialize a new array of all the students
    let filteredStudents: Array<Student> = this.students;
    if (value.sex) {
      // if filter for sex is set, simply filter for any student that has the same value for sex
      filteredStudents = filteredStudents.filter((student: Student) => student.sex === value.sex);
    }
    if (value.category && !value.status) {
      // when category is set but status is not, filter for any student that has the category in any of its programs 
      filteredStudents = filteredStudents.filter((student: Student) => {
        return student.programs
          .map((program: Program) => program.programCategory)
          .includes(value.category);
      });
    }
    if (!value.category && value.status) {
      // when status is set but category is not, filter for any student that has the status in any of its programs
      filteredStudents = filteredStudents.filter((student: Student) => {
        return student.programs
          .map((program: Program) => program.programStatus)
          .includes(value.status);
      });
    }
    if (value.category && value.status) {
      // when category and status is both set, filter for any student that has the status AND category in any of its programs
      filteredStudents = filteredStudents.filter((student: Student) => {
        return student.programs
          .filter((program: Program) => program.programCategory === value.category)
          .map((program: Program) => program.programStatus)
          .includes(value.status);
      });
    }
    // set the filtered students to display
    this.filteredStudents = filteredStudents;
  }

}

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">

          <form [formGroup]="filterForm">

            <div class="row">

              <div class="col-sm-4">
                <div class="form-group">
                  <label for="exampleSelect1">Sex</label>
                  <div class="row">
                    <div class="col-sm-9">
                      <select class="form-control" formControlName="sex">
                        <option value="">All</option>
                        <option *ngFor="let option of sexOptions" [value]="option">{{ option }}</option>
                    </select>
                    </div>
                    <div class="col-sm-3">
                      <button class="btn btn-primary" *ngIf="filterForm && !!filterForm.get('sex').value" (click)="filterForm.get('sex').setValue('')">Clear</button>
                    </div>
                  </div>
                </div>
              </div>
              <div class="col-sm-4">
                <div class="form-group">
                  <label for="exampleSelect1">ProgramCategory</label>
                  <div class="row">
                    <div class="col-sm-9">
                      <select class="form-control" formControlName="category">
                        <option value="">All</option>
                        <option *ngFor="let option of programCategoryOptions" [value]="option">{{ option }}</option>
                    </select>
                    </div>
                    <div class="col-sm-3">
                      <button class="btn btn-primary" *ngIf="filterForm && !!filterForm.get('category').value" (click)="filterForm.get('category').setValue('')">Clear</button>
                    </div>
                  </div>
                </div>
              </div>
              <div class="col-sm-4">
                <div class="form-group">
                  <label for="exampleSelect1">ProgramStatus</label>
                  <div class="row">
                    <div class="col-sm-9">
                      <select class="form-control" formControlName="status">
                        <option value="">All</option>
                        <option *ngFor="let option of programStatusOptions" [value]="option">{{ option }}</option>
                    </select>
                    </div>
                    <div class="col-sm-3">
                      <button class="btn btn-primary" *ngIf="filterForm && !!filterForm.get('status').value" (click)="filterForm.get('status').setValue('')">Clear</button>
                    </div>
                  </div>
                </div>
              </div>
            </div>

          </form>

        </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 student of filteredStudents">
                  <td>{{ student.studentId }}</td>
                  <td>{{ student.studentName }}</td>
                  <td>{{ student.sex }}</td>
                  <td>
                    {{ student.programs.length }}
                    <ol *ngFor="let program of student.programs">
                      <li>{{ program.programCategory }} / {{ program.programStatus }}</li>
                    </ol>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
0
bodorgergely