Search code examples
angularmaterial-uiangular-materialangular-material-15angular-material-11

Not able to sort data correspoing to column in header in Angular material Table


clinical history data the output i m getting that not by order asc desc

I'm trying to sort the data that I have in the table, and I use the MatTableModule module with the required other modules.

but I did research but didn't get a satisfactory answer.

this is my TS file

import { AfterViewInit, Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { MatSort, Sort } from '@angular/material/sort';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { MatPaginator } from '@angular/material/paginator';
import { Router } from '@angular/router';
import { EmrService } from '../../services/emr.service';
import { ToastrService } from 'ngx-toastr';
import { patient } from '../../interface/patient';
import { LiveAnnouncer } from '@angular/cdk/a11y';

export interface UserData {
  PatientId: any;
  ClinicalEventDate: any;
  clinicalEventType: any;
  reportType: any;
  clinicalDetails: any;
}


@Component({
  selector: 'app-clinic-history',
  templateUrl: './clinic-history.component.html',
  styleUrls: ['./clinic-history.component.css'],
})

export class ClinicHistoryComponent implements OnInit, AfterViewInit {

  displayedColumns: string[] = ['ClinicalEventDate', 'clinicalEventType', 'reportType', 'clinicalDetails'];
  dataSource!: MatTableDataSource<UserData>;

  @ViewChild(MatPaginator) paginator!: MatPaginator;
  @ViewChild(MatSort, { static: true }) sort!: MatSort;
  @ViewChild('input') input!: ElementRef;
  IsLoading: boolean = true;
  PatientData!: patient;
  esteblishment_id: any;
  data!: UserData[] | undefined;

  visitTypeMap: { [key: number]: string } = {
    1: 'In Patient',
    2: 'Out Patient',
    3: 'Emergency',
    4: 'Day Care',
  };
  constructor(private router: Router, public emrservice: EmrService, private toaster: ToastrService, private _liveAnnouncer: LiveAnnouncer) {

  }

  ngOnInit(): void {
    console.log('nginit');
    let userData: any = localStorage.getItem('userdata');
    userData = JSON.parse(userData);
    if (userData?.esteblishment_user_map_id) {
      this.esteblishment_id = userData.esteblishment_user_map_id;
      this.emrservice.patientData$.subscribe((res: patient | null) => {
        if (res) {
          this.PatientData = res;
          let patientId = this.PatientData.patient_id;
          if (patientId) {
            // this.cdr.detectChanges();
            this.getClinicalHistory(patientId);
          }
        }
      })
    }
  }


  ngAfterViewInit(): void {
    console.log('ngafter')
  }

  getClinicalHistory(patientId: any) {
    this.IsLoading = true;
    this.emrservice.viewPastHistory(this.esteblishment_id, patientId).subscribe({
      next: (res: any) => {
        console.log('view past clinical history data', res);
        if (res.status) {
          this.data = res.data;
          this.dataSource = new MatTableDataSource(this.data);
          this.dataSource.paginator = this.paginator;
          // this.data = undefined;
          // this.dataSource = new MatTableDataSource(undefined);
          this.dataSource.sort = this.sort;
          setTimeout(() => {
            this.IsLoading = false;
          }, 500);
        } else {
          setTimeout(() => {
            this.IsLoading = false;
            this.data = undefined;
            this.dataSource = new MatTableDataSource(undefined);
            this.toaster.warning("", "No records found");
          }, 500);
        }
      },
      error: (err: any) => {
        console.log(err);
        this.data = undefined;
        this.dataSource = new MatTableDataSource(undefined);
        setTimeout(() => {
          this.IsLoading = false;
        }, 500);
        this.toaster.error("", "Something went wrong");
      }
    })
  }

  applyFilter(event: Event) {
    const filterValue = (event.target as HTMLInputElement).value;
    this.dataSource!.filter = filterValue.trim().toLowerCase();
    if (this.dataSource!.paginator) {
      this.dataSource!.paginator.firstPage();
    }
  }

  onDiagnostic(value: any) {
    if (value == 'Diagnostic Report') {
      this.router.navigate(['doctor/emr/patient/diagnostic-report'])
    } else if (value == 'Op Consultation') {
      this.router.navigate(['doctor/emr/patient/op-consultation'])

    } else if (value == 'Discharge Summary') {
      this.router.navigate(['doctor/emr/patient/discharge-summary'])

    } else if (value == 'Record Prescription') {
      this.router.navigate(['doctor/emr/patient/record-prescription'])

    }
  }

  onMatSortChange(s: any) {
    console.log("matsorchanging")
  }

  Error() {
    return `❌ Not Found ${this.input.nativeElement.value}`
  }
}

this is my html file

<div class="header">View Past Clinical History recorded in this facility</div>
<mat-form-field appearance="standard" class="w-75 mb-2">
  <input matInput (keyup)="applyFilter($event)" placeholder="Ex. Aug 18 2023" #input />
  <span matPrefix><mat-icon class="search-icon">search</mat-icon>&nbsp;</span>
</mat-form-field>

<div class="mat-elevation-z8 overflow-auto">
  <table mat-table [dataSource]="dataSource" matSort class="w-100" matSortActive="created" matSortDisableClear
    matSortDirection="desc">
    <ng-container matColumnDef="ClinicalEventDate">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>
        Clinical Event Date
      </th>
      <td mat-cell *matCellDef="let row" class="wrap">
        {{ this.emrservice.convertTowDDDMMYYYYTime(row.created_at) }}
      </td>
    </ng-container>
    <ng-container matColumnDef="clinicalEventType">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>Clinical Event Type</th>
      <td mat-cell *matCellDef="let row" class="wrap">
        {{ visitTypeMap[row.visit_type] }}
      </td>
    </ng-container>
    <ng-container matColumnDef="reportType">
      <th mat-header-cell *matHeaderCellDef>Record Type</th>
      <td mat-cell *matCellDef="let row" class="wrap">{{ row.type }}</td>
    </ng-container>
    <ng-container matColumnDef="clinicalDetails">
      <th mat-header-cell *matHeaderCellDef>Clinical Details</th>
      <td mat-cell *matCellDef="let row" class="wrap">
        <a class="btn-sm link-primary pointer" (click)="onDiagnostic(row.type)">Click Here</a>
      </td>
    </ng-container>

    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>

    <tr class="mat-row" *matNoDataRow>
      <td class="mat-cell" colspan="7" class="wrap text-center">
        <div class="d-flex justify-content-center align-items-center py-2">
          {{ this.data ? Error() : "❌ Data not available" }}
        </div>
      </td>
    </tr>
  </table>
  <mat-paginator class="w-100" [pageSizeOptions]="[5, 10, 25, 100]" aria-label="Select page of users"></mat-paginator>
</div> 

this is my module file where this component is registered

import { NgModule } from '@angular/core';
import { CommonModule, DatePipe } from '@angular/common';

import { PatientRoutingModule } from './patient-routing.module';
import { PatientComponent } from './patient.component';
import { ClinicHistoryComponent } from './clinic-history/clinic-history.component';
import { DiagnosticReportComponent } from './diagnostic-report/diagnostic-report.component';
import { OpConsultationComponent } from './op-consultation/op-consultation.component';
import { DischargeSummaryComponent } from './discharge-summary/discharge-summary.component';
import { RecordPrescriptionComponent } from './record-prescription/record-prescription.component';
import { MatTableModule } from '@angular/material/table';
import { MatSortModule } from '@angular/material/sort';
import { MatFormFieldModule } from '@angular/material/form-field';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatInputModule } from '@angular/material/input';
import { MatPaginatorModule } from '@angular/material/paginator';
import { MatIconModule } from '@angular/material/icon';
import { MatRadioModule } from '@angular/material/radio';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { TextFieldModule } from '@angular/cdk/text-field';
import { MatButtonModule } from '@angular/material/button';
import { LoaderForEmrModule } from '../loader-for-emr/loader-for-emr.module';
import { MatDialogModule } from '@angular/material/dialog';
import { PdfViewerComponent } from './pdf-viewer/pdf-viewer.component';
import { SafePipe } from 'src/app/safe.pipe';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
@NgModule({
  declarations: [
    PatientComponent,
    ClinicHistoryComponent,
    DiagnosticReportComponent,
    OpConsultationComponent,
    DischargeSummaryComponent,
    RecordPrescriptionComponent,
    PdfViewerComponent,
    SafePipe
  ],
  imports: [
    ReactiveFormsModule,
    FormsModule,
    CommonModule,
    PatientRoutingModule,
    MatTableModule,
    MatSortModule,
    MatFormFieldModule,
    MatInputModule,
    MatPaginatorModule,
    MatIconModule,
    MatRadioModule,
    MatDatepickerModule,
    TextFieldModule,
    MatButtonModule,
    LoaderForEmrModule,
    MatDialogModule,
    MatProgressSpinnerModule
  ],
  providers: [DatePipe]
})
export class PatientModule { }

I have to sort the data, correspoding to column


Solution

  • I imagine you have a "loading" and, when the loading is visible, the table not.

    This is the reason Angular can not "reach" the mat-sort. Futhermore if you write static:true} Angular only "search" the mat-sort at very stage on your component, if not present never check if it come to scene

    getClinicalHistory(patientId: any) {
        this.IsLoading = true;
        this.emrservice.viewPastHistory(this.esteblishment_id, patientId).subscribe({
          next: (res: any) => {
            console.log('view past clinical history data', res);
            this.IsLoading = false; //<--first isLoading=false
            //then in a setTimeout without any seconds 
            setTimeout(()=>{
               if (res.status) {
                    this.data = res.data;
                    this.dataSource = new MatTableDataSource(this.data);
                    this.dataSource.paginator = this.paginator;
               } else {
                 this.data = undefined;
                 this.dataSource = new MatTableDataSource(undefined);
                 this.toaster.warning("", "No records found");
               }
             })
          },
          error: (err: any) => {
            console.log(err);
            this.data = undefined;
            this.dataSource = new MatTableDataSource(undefined);
            this.toaster.error("", "Something went wrong");
          }
        })
      }
    

    Update About your problem:

    I just see what can happens. When you use MatSort, by defect,you only can sort by the "property" you defined in the reportType, e.g. when you write

    <!--see that you write matColumnDef--->
    <ng-container matColumnDef="ClinicalEventDate">
          <th mat-header-cell *matHeaderCellDef mat-sort-header>
            Clinical Event Date
          </th>
          ...
    </ng-container>
    

    You sort only if your elements have a property: ClinicalEventDate

    I imagine should be

    <!--see that the matColumnDef is create_at-->
    <ng-container matColumnDef="created_at">
          <th mat-header-cell *matHeaderCellDef mat-sort-header>
            Clinical Event Date
          </th>
          ...
    </ng-container>
    

    And you need change displayedColumns array

    It's also posible indicate in mat-sort-header any "property", so, e.g.

    <!--see that you write matColumnDef--->
    <ng-container matColumnDef="ClinicalEventDate">
          <!--but you order by another "property"-->
          <th mat-header-cell *matHeaderCellDef mat-sort-header="created_at">
            Clinical Event Date
          </th>
          ...
    </ng-container>
    

    This allow, e.g. when we have a date, create a new property in the way yyyyMMdd and show one property but order by this "auxiliar property". See for inspiration, e.g. this SO that create an auxiliar property 'normalized' to sort the IPs.