Home > Software design >  Angular mat-table sort column that displays from a function
Angular mat-table sort column that displays from a function

Time:12-02

What is the proper way to sort a mat-table which has one column that displays a description rather than the code of a mat-select. Consider the following code example that is an editable mat-table which displays a description of the selected item from the mat-select column in edit mode, when not in edit mode. That means when the grid isn't in edit mode, I call a function to give me the description to display.

In static mode:

<div *ngIf="col.key == 'MGA_ServiceDescription'">
    <span >
        {{ getServiceDescription(element[col.key]) }}
    </span>
</div>

In Edit mode:

mat-form-field *ngSwitchCase="'listServiceDescriptions'" >
   <mat-select [(value)]="element[col.key]">
       <mat-option *ngFor="let c of filteredServices" [value]="c.SDE_CODE"
           {{ c.SDE_DESCRIPTION}}
       </mat-option>
   </mat-select>
/mat-form-field>

Code example

CodePudding user response:

The sortingDataAccessor takes in the current row and the sort attribute. As you're working on the "occupation", property = occupation, items will be USER_DATA

sortingDataAccessor applied for all columns so we need to check if it's the column we're interested in. That's why we need a switch/case.
In the 'occupation' column, you have a map occupationsList which maps X => A, Y => B, Z => C... We want that instead of sorting by X/Y/Z, it should sort by A/B/C => return A/B/C instead, that's why I return description (the mapped value)

this.dataSource = new MatTableDataSource(USER_DATA);
    this.dataSource.sortingDataAccessor = (item, property) => {
      switch(property) {
        case 'occupation': occupationsList.find(o => o.name === item.occupation).description;
        default: return item[property];
      }
    };
    this.dataSource.sort = this.sort;

CodePudding user response:

The "best way" when we have an array and one property really is a "select" is add to the array the "description"

Imagine some like

  ngOnInit() {
    this.dataSource = new MatTableDataSource(
      USER_DATA.map((code: any) => {
        const serviceDescription = this.serviceDescriptions.find(
          (desc: any) => desc.SDE_CODE === code.MGA_ServiceDescription
        );
        return {
          ...code,
          description: serviceDescription? serviceDescription.SDE_DESCRIPTION: '',
        };
      })
    );
  }

Well, ther're some problems. The first is change the "sortHeader", we wnat tha t, when the column was 'MGA_ServiceDescription' sort by the new property, so:

<th
        mat-header-cell
        *matHeaderCellDef
        [mat-sort-header]="col.key=='MGA_ServiceDescription'?'description':col.key"
        [disabled]="col.key == 'isEdit'"
      >

The another problem is how "edit" the element. If we use a mat-select we can choose that the value of the options was the "SDE_CODE" or the own serviceDescription.

I'm going to select the whole object. But for this we need a compareWith function

serviceCompareWith=(a:any, MGA_ServiceDescription:any)=>
                             a.SDE_CODE==MGA_ServiceDescription

And, when change change the two properties, the "MGA_ServiceDescription" and the "description"

  change(value:any,element:any)
  {
    element.MGA_ServiceDescription=value.SDE_CODE;
    element.description=value.SDE_DESCRIPTION
  }

Now our "mat-select" becomes like

<mat-select [compareWith]="serviceCompareWith" 
            [value]="element.MGA_ServiceDescription"  
            (selectionChange)="change($event.value,element)">
        <mat-option *ngFor="let service of serviceDescriptions" [value]="service">
          {{service.SDE_DESCRIPTION}}
        </mat-option>
</mat-select>
  • Related