0
votes

I have a primeng table where on column value is obtained from a nested object.I am unable to filter the table using that column value.The filter works fine if enter value present in other columns.Please help.Thanks in advance.

Here is my typescript:

this.cols = [
      { field: 'name', header: 'Name' },
      { field: 'email', header: 'Email' },
      { field: 'phnNumber', header: 'Contact No' },
      { field: 'grades[0].grade1', header: 'Grade' },

    ];

here is my filter:

   <div class="col-md-6">
    <p-table [columns]="cols" #dt [value]="students" [autoLayout]="true" [paginator]="true" [rows]="10">
        <ng-template pTemplate="caption">
            <div style="text-align: right">
                <i class="fa fa-search" style="margin:4px 4px 0 0"></i>
                <input type="text" pInputText size="30" placeholder="Search" (input)="dt.filterGlobal($event.target.value, 'contains')" class="filter">
            </div>
        </ng-template>
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th class="row-header" *ngFor="let col of columns" [pSortableColumn]="col.field">
                    {{col.header}}
                    <p-sortIcon class="" [field]="col.field" ariaLabel="Activate to sort" ariaLabelDesc="Activate to sort in descending order" ariaLabelAsc="Activate to sort in ascending order">
                    </p-sortIcon>
                </th>

            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-student let-columns="columns">
            <tr class="center-text">
                <td class="row-cell">{{student.name}}</td>
                <td class="row-cell">
                    {{student.email}}
                </td>

                <td class="row-cell">{{student.grades[0].grade1}}</td>

            </tr>
        </ng-template>
    </p-table>

</div>

If I enter any value present in the grade column,I get empty response. I think there's some issue with using grades[0].grade1 as field.

JSON Structure:

[
    {
        "name": "Test",
        "email": null,
        "phnNumber": 1,
        "grades": [
            {
                "grade1": "A",
                "grade2": "B"
            }
        ]
    }
]

Stackblitz- https://stackblitz.com/edit/angular-dbwfep

1
Which column filter is not working ? can you add full html code to understand your question?CodeChanger
@CodeChanger please see now.rock11
can you share student structure, here name seems like string and next moment you are using as an array? <td class="row-cell">{{student.name}}</td> And <td class="row-cell">{{student.name[0].grade}}</td>Abhinav Kumar

1 Answers

0
votes

You can use name[0].grade as filed property in column configuration. It can be any nested object. Filter is working.

The fact is that data on the table should the same property.

Update: You have to implement custom sorting and filter method of the table. Sorting is dynamic, as we know on which filed user want to sort based on click event, identifying the key is easy. But in the filter we don't know, the filter works for all the fields, so I have taken the 'grade1' field as of now to filter, you can add as many as field and remove after the filter.

I guess in case of a nested object, it doesn't work default, so you have to add custom implementation. Hope this helps.

component.html

<hello name="{{ title }}"></hello>
<div class="col-md-6">
    <p-table [columns]="cols" #dt [value]="students" [autoLayout]="true" [paginator]="true" [rows]="10" (onSort)="onSort($event)">
        <ng-template pTemplate="caption">
            <div style="text-align: right">
                <i class="fa fa-search" style="margin:4px 4px 0 0"></i>
                <input type="text" pInputText size="30" placeholder="Search" (input)="myFilter($event)" class="filter">
            </div>
        </ng-template>
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th class="row-header" *ngFor="let col of columns" [pSortableColumn]="col.field">
                    {{col.header}}
                    <p-sortIcon class="" [field]="col.field" ariaLabel="Activate to sort" ariaLabelDesc="Activate to sort in descending order" ariaLabelAsc="Activate to sort in ascending order">
                    </p-sortIcon>
                </th>

            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-student let-columns="columns">
            <tr class="center-text">
                <td class="row-cell">{{student.name}}</td>
                <td class="row-cell">
                    {{student.email}}
                </td>
                <td class="row-cell">
                    {{student.phnNumber}}
                </td>
                <td class="row-cell">{{student.grades[0].grade1}}</td>

            </tr>
        </ng-template>
    </p-table>

</div>

component.ts

import { FormControl, FormGroup } from "@angular/forms";
import { Component,
         ViewChild,
         AfterViewInit,
         ElementRef } from '@angular/core';
@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
export class AppComponent {
  title = "Filter in Table";
  cols = [];
  grades = [{ grade1: "grade1", grade2: "grade2" }];
  students = [];
  @ViewChild('dt',{read: '',static:true}) dt: any;

  constructor() {
    this.cols = [
      { field: "name", header: "Name" },
      { field: "email", header: "Email" },
      { field: "phnNumber", header: "Contact No" },
      { field: this.grades[0]["grade1"], header: "Grade1" }
    ];
    this.students = [
      {
        name: "Abhinav",
        email: "[email protected]",
        phnNumber: "23456787654",
        grades: [
          {
            grade1: "AA",
            grade2: "X"
          }
        ]
      },
      {
        name: "Ravi",
        email: "[email protected]",
        phnNumber: "1234543666",
        grades: [
          {
            grade1: "CC",
            grade2: "Y"
          }
        ]
      },
      {
        name: "Harsh",
        email: "[email protected]",
        phnNumber: "23212324",
        grades: [
          {
            grade1: "BB",
            grade2: "Z"
          }
        ]
      }
    ];
  }
  myFilter(e){
    this.dt.value.forEach((e)=>{
      e['grade1'] = e['grades'][0]['grade1'];
    });
    this.dt.filterGlobal(e.target.value, 'contains');
    setTimeout(()=>{
      this.dt.value.forEach((e)=>{
      delete e['grade1'];
    });
    },500)
  }
  onSort(e){
    let filed = e.field;
    let arr = [...this.students];
    if(filed === 'grade1'){
      // custome sort only for these fields

      let order = e.order; // 1 means abc and -1 means cba
      if(order === 1){
        this.students.sort( this.OrderListBy(filed) );
      }else{
        this.students.sort( this.OrderListBy(filed) ).reverse();
      }
    }
  }
  OrderListBy(prop) {
    return function (a, b) {
        if (a['grades'][0][prop] > b['grades'][0][prop]) {
            return 1;
        }
        else if (a['grades'][0][prop] < b['grades'][0][prop]) {
            return -1;
        }
        return 0;
    }
  }
}

see updated working example