Search code examples
angulartypescriptangular-materialmat-table

Can I sort by selected rows using a MatTable?


I have a MatTable which implements selection as indicated by Angular Material's documentation

Everything works fine, selection is made, etc; but I was thinking if its possible to apply some kind of sorting so I can sort the DataSource so the selected rows are shown first.

<table mat-table matSort [dataSource]="dataSourcePPC" class="w-100 table-bordered table-hover">
   <ng-container matColumnDef="select">
       <th mat-header-cell *matHeaderCellDef></th>
       <td mat-cell *matCellDef="let row" class="text-center">
          <mat-checkbox (click)="$event.stopPropagation()" (change)="$event ? selectionPPC.toggle(row) : null;"
                        [checked]="selectionPPC.isSelected(row)">
          </mat-checkbox>
       </td>
   </ng-container>
   <ng-container matColumnDef="type">
       <th mat-header-cell *matHeaderCellDef mat-sort-header> Type </th>
       <td mat-cell *matCellDef="let ppc">{{ ppcTypeModel[ppc.type] }}</td>
   </ng-container>

   ...

   <tr mat-header-row *matHeaderRowDef="displayedColumnsPPC"></tr>
   <tr mat-row *matRowDef="let row; columns: displayedColumnsPPC;" [ngClass]="{'selected': selectionPPC.isSelected(row)}" (click)="selectionPPC.toggle(row)"></tr>
</table>

I'm looking into the sortingDataAccesor function but I really don't understand how it works; any help regarding this is appreciated.


Solution

  • you can do something like this.

    this is how checkbox works.

      <ng-container matColumnDef="select">
        <th mat-header-cell *matHeaderCellDef>
          <mat-checkbox (change)="$event ? masterToggle() : null" [checked]="selection.hasValue() && isAllSelected()"
            [indeterminate]="selection.hasValue() && !isAllSelected()" [aria-label]="checkboxLabel()">
          </mat-checkbox>
          <div mat-sort-header>
            <mat-icon>ac_unit</mat-icon>
          </div>
        </th>
        <td mat-cell *matCellDef="let row">
          <mat-checkbox (click)="$event.stopPropagation()" (change)="$event ? selection.toggle(row) : null"
            [checked]="selection.isSelected(row)" [aria-label]="checkboxLabel(row)">
          </mat-checkbox>
        </td>
      </ng-container>
    

    and in typescript you write.

    this.dataSource.sortingDataAccessor = (item, property) => {
            switch (property) {
              case 'select': return this.selection.selected.includes(item);
              case 'nestedObject': return item.parentObject.childObject;
              default: return item[property];
            }
          };
    

    basically since my matColumnDef is 'select' when the data is passed to sortingDataAccessor you need to check if it matches 'select'. once you know it matche 'select' you can check if your item (meaning the current row) is included in the array of selected items ( selection.selected array ).

    selection = new SelectionModel(true, []); // you already should have this since you have select.
    

    I also included how to sort in nested objects. If you need it. if you have nested object you will need to write something like case 'nestedObject' in switchcase. 'nestedObject' is just whatever you call your column in table.

    I checked it in my project and it works fine.

    Good luck!