Angular Material sorting not able to sort columns

  angular, angular-material, typescript

I have implemented mat sort in two components using the same method. In one component is working fine but in other component it is not working due to some reason I am unable to find. I also checked the property should be same and in my code 2 of property out of all are according to the format but even those columns are not getting sorted.

Below is the code

HTML code

<!-- <section class="content-header">
  <div class="container-fluid">
    <h1>Patient Listing</h1>
  </div>
</section> -->

<mat-form-field appearance="fill">
        <mat-label>Enter a date range</mat-label>
        <mat-date-range-input [formGroup]="dateRangeFormGroup" [rangePicker]="picker" >
            <input matStartDate formControlName="start" placeholder="Start date" [disabled]="true">
            <input matEndDate formControlName="end" placeholder="End date" [disabled]="true">
        </mat-date-range-input>
        <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
        <mat-date-range-picker #picker disabled="false">
            <mat-date-range-picker-actions>
                <button mat-button matDateRangePickerCancel>Cancel</button>
                <button mat-raised-button color="primary" matDateRangePickerApply (click)="onDateRangeApply()">Apply</button>
              </mat-date-range-picker-actions>
        </mat-date-range-picker>

        <mat-error *ngIf="dateRangeFormGroup.get('start').hasError('matStartDateInvalid')">Invalid start date
        </mat-error>
        <mat-error *ngIf="dateRangeFormGroup.get('end').hasError('matEndDateInvalid')">Invalid end date</mat-error>
</mat-form-field>

<mat-form-field>
    <mat-label>Search</mat-label>
    <input matInput (keyup)="applyFilter($event)" placeholder="Ex. Anything" #input>
  </mat-form-field>


<button class="float-right add-record-btn" mat-raised-button color="primary" (click)="onRecordEdit()">Add
    Record</button>

<div class="mat-elevation-z8">
    <table mat-table [dataSource]="recordInformation" matSort *ngIf="recordInformation">

        <ng-container matColumnDef="firstName">
            <th mat-header-cell *matHeaderCellDef mat-sort-header> First Name </th>
            <td mat-cell *matCellDef="let record"> {{record.patientInformation.firstName | emptyString}} </td>
            <td mat-footer-cell *matFooterCellDef></td>
        </ng-container>

        <ng-container matColumnDef="lastName">
            <th mat-header-cell *matHeaderCellDef mat-sort-header> Last Name </th>
            <td mat-cell *matCellDef="let record"> {{record.patientInformation.lastName | emptyString}} </td>
            <td mat-footer-cell *matFooterCellDef></td>
        </ng-container>

        <ng-container matColumnDef="treatment">
            <th mat-header-cell *matHeaderCellDef mat-sort-header> Treatment </th>
            <td mat-cell *matCellDef="let record"> {{record.treatment | emptyString}} </td>
            <td mat-footer-cell *matFooterCellDef> Total </td>
        </ng-container>

        <ng-container matColumnDef="amount">
            <th mat-header-cell *matHeaderCellDef mat-sort-header> Amount </th>
            <td mat-cell *matCellDef="let record"> {{record.amount}} </td>
            <td mat-footer-cell *matFooterCellDef> {{getTotalAmount() | currency:'INR'}} </td>
        </ng-container>


        <ng-container matColumnDef="recordActions">
            <th mat-header-cell *matHeaderCellDef>Actions </th>
            <td mat-cell *matCellDef="let record">
                <button mat-icon-button [matMenuTriggerFor]="menu" aria-label="Example icon-button with a menu">
                    <mat-icon>more_vert</mat-icon>
                </button>
                <mat-menu #menu="matMenu">
                    <button mat-menu-item (click)="onRecordEdit(record)">
                        <mat-icon>edit</mat-icon>
                        <span>Edit Record</span>
                    </button>
                    <button mat-menu-item (click)="onRecordDelete(record.id)">
                        <mat-icon>delete</mat-icon>
                        <span>Delete Record</span>
                    </button>
                </mat-menu>

            </td>
            <td mat-footer-cell *matFooterCellDef></td>
        </ng-container>
        <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
        <tr class="element-row" mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
        <tr class="total-footer-row" mat-footer-row *matFooterRowDef="displayedColumns; sticky: true"></tr>
        <tr class="mat-row" *matNoDataRow>
            <td class="mat-cell" colspan="4">No data</td>
        </tr>
    </table>
    <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]" [pageSize]=25></mat-paginator>
</div>

ts code

import { Component, OnInit, ViewChild } from '@angular/core';
import { LoadingService } from 'src/app/shared/loading.service';
import { PatientService } from '../patient.service';
import { RecordInformationModel } from 'src/app/models/records/RecordInformationModel';
import { MatTableDataSource } from '@angular/material/table';
import { MatSort } from '@angular/material/sort';
import { MatPaginator } from '@angular/material/paginator';
import { GuidModel } from 'src/app/models/common/GuidModel';
import { MatDialog } from '@angular/material/dialog';
import { EditRecordComponent } from './edit-record/edit-record.component';
import { ConfirmDialogComponent } from '../../shared/components/confirm-dialog/confirm-dialog.component';
import { FormBuilder, FormGroup } from '@angular/forms';
import { DateRangeModel } from 'src/app/models/records/DateRangeModel';
import { ToasterService } from '../../shared/toaster.service';

@Component({
  selector: 'app-record-list',
  templateUrl: './record-list.component.html',
  styleUrls: ['./record-list.component.scss']
})
export class RecordListComponent implements OnInit {

  displayedColumns: string[] = ['firstName', 'lastName', 'treatment', 'amount', 'recordActions'];
  @ViewChild(MatSort) sort: MatSort;
  @ViewChild(MatPaginator) paginator: MatPaginator;
  recordInformation: MatTableDataSource<RecordInformationModel>;
  isAllInformation: boolean;
  dateRangeFormGroup: FormGroup;

  constructor(private loading: LoadingService,
    private patientService: PatientService,
    public dialog: MatDialog,
    private fb: FormBuilder,
    private toasterService: ToasterService) { }

  ngOnInit() {
    this.initForm();
    this.loadNext();
  }

  initForm() {
    this.dateRangeFormGroup = this.fb.group({
      start: [new Date()],
      end: [new Date()]
    })
  }
  loadNext() {
    this.loading.show();
    this.isAllInformation = false;
    this.patientService.getAllRecords(this.getDateRangeValue()).subscribe(res => {
      this.recordInformation = new MatTableDataSource(res);
      this.recordInformation.sort = this.sort;
      this.recordInformation.paginator = this.paginator;
      
      this.isAllInformation = true
      this.loading.hide();
    }, error => {
      this.toasterService.error("Failed", error.error);
      this.loading.hide();
    })
  }

  onRecordEdit(recordInformation: RecordInformationModel = {
    id: new GuidModel().Empty,
    patientId: new GuidModel().Empty,
    recordDate: null,
    amount: null,
    treatment: null,
    patientInformation: null
  }) {
    const dialogRef = this.dialog.open(EditRecordComponent, {
      disableClose: true,
      data: recordInformation
    });

    dialogRef.afterClosed().subscribe(result => {
      if (result) {
        this.loadNext();
      }
    });
  }

  onRecordDelete(recordId: string) {
    const dialogRef = this.dialog.open(ConfirmDialogComponent, {
      data: { title: 'Delete Record?', message: 'Are you sure you want to permanently delete the record' }
    })

    dialogRef.afterClosed().subscribe(result => {
      if (result) {
        this.loading.show();
        this.patientService.deleteRecord(recordId).subscribe(() => {
          this.loadNext();
          this.toasterService.success("Success", "Record deleted Successfully");
          this.loading.hide();
        })
      }
    })
  }

  applyFilter(event: Event) {
    const filterValue = (event.target as HTMLInputElement).value;
    this.recordInformation.filter = filterValue.trim().toLowerCase();

    this.recordInformation.filterPredicate = (data, filter: string)  => {
      const accumulator = (currentTerm, key) => {
        return key === 'patientInformation' ? currentTerm + data.patientInformation.firstName + data.patientInformation.lastName : currentTerm + data[key];
      };
      const dataStr = Object.keys(data).reduce(accumulator, '').toLowerCase();
      // Transform the filter by converting it to lowercase and removing whitespace.
      const transformedFilter = filter.trim().toLowerCase();
      return dataStr.indexOf(transformedFilter) !== -1;
    };
  }

  onDateRangeApply() {
    this.loading.show();
    this.isAllInformation = false;
    this.patientService.getAllRecords(this.getDateRangeValue()).subscribe(res => {
      this.recordInformation = new MatTableDataSource(res);
      this.isAllInformation = true;
      this.recordInformation.sort = this.sort;
      this.recordInformation.paginator = this.paginator;
      this.loading.hide();
    }, error => {
      this.toasterService.error("Failed", error.error);
      this.loading.hide();
    })
  }

  getDateRangeValue() {
    let dateRangeFormGroupData = this.dateRangeFormGroup.value;
    let dateRange: DateRangeModel = {
      startDate: this.formatDate(dateRangeFormGroupData.start),
      endDate: this.formatDate(dateRangeFormGroupData.end)
    }
    return dateRange;
  }
  getTotalAmount() {
    let total = 0;
    this.recordInformation.data.forEach(record => {
      total = total + record.amount;
    })
    return total;
  }

  formatDate(date: Date) {
    if (date != null) {
      var offsetMs = date.getTimezoneOffset() * 60000;
      return new Date(date.getTime() - offsetMs);
    }
    else {
      return null;
    }
  }
}

Source: Angular Material Quesions

One Reply to “Angular Material sorting not able to sort columns”

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.