mightycode Newton
mightycode Newton

Reputation: 3949

Angular Material sorting, Cannot set property 'sort' of undefined

I have a Angular 8 application that uses Angular Material. I want to sort the colums in a angular 8 application, using Angular Material

googled, courses

So this is how the file looks where sorting is implemented ts file looks like:

import { ActivatedRoute } from '@angular/router';
import { Component, OnInit, ViewChild, Inject, Input } from '@angular/core';
import { QRCodeDefinitionInfoApi, EcheqSubmissionInfoApi, QRCodeMedicalService } from 'src/app/generated';
import { MatPaginator, MatSort } from '@angular/material';
import { MAT_DIALOG_DATA, MatTableDataSource } from '@angular/material';
import { PublishState } from 'src/app/qrcode-definition/list/list-item';
import { I18n } from '@ngx-translate/i18n-polyfill';

class SortedSubmissions {
  [key: string]: {
    submissions: EcheqSubmissionInfoApi[];
  };
}


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

  @ViewChild(MatPaginator) paginator: MatPaginator;
  @ViewChild(MatSort) sort: MatSort;

  readonly ScanFequencyType = QRCodeDefinitionInfoApi.ScanFrequencyTypeEnum;
  readonly PublishState = QRCodeDefinitionInfoApi.PublishStateEnum;
  readonly ActionType = QRCodeDefinitionInfoApi.ActionTypeEnum;
  source: QRCodeDefinitionInfoApi[];
  datasource: MatTableDataSource<QRCodeDefinitionInfoApi>;

  patientId: string;
  submissions: EcheqSubmissionInfoApi[];


  @Inject(MAT_DIALOG_DATA) public data: any;
  @Input() item;
  sortedSubmissions: SortedSubmissions;

  public readonly displayedColumns = [

    'title',
    'lastScannedOn',
    'totalScanned',
    'publishState',
  ];

  constructor(private i18n: I18n, route: ActivatedRoute,  private qrCodeDefintion: QRCodeMedicalService ) {

    this.patientId = route.snapshot.paramMap.get('patientId');
    const data = route.snapshot.data;
    this.source = data.definition;

    }

  ngOnInit() {

    this.qrCodeDefintion.getQRCodeList(1, this.patientId).subscribe((subs) => {
    (this.source = subs);
    });

    if (this.data && this.data.definition) {
      this.source = this.data.definition;
    }
    // this.datasource.paginator = this.paginator;
    this.datasource.sort = this.sort;
  }

  translatePublished(publishState: PublishState): string {
    switch (publishState) {
      case PublishState.DRAFT:
        return this.i18n('Not published');
      case PublishState.PUBLISHED:
        return this.i18n('Published');
    }
    switch ( String(publishState) ) {
      case 'Draft':
          return this.i18n('Not published');
      case 'Published':
        return this.i18n('Published');
      default:
        return this.i18n( 'Not Published' );
    }
  }
}

and this is the html of the page:

<div class="header">
    <h1 class="heading page-heading patient-list-heading">Scanned QR Codes </h1>
  <div class="qrcode-menu">
  </div>
</div>

  <div class="mat-elevation-z8">
    <table
      mat-table
      class="full-width-table"
      [dataSource]="source"
      matSort
      aria-label="Elements"
    >
    <ng-container matColumnDef="title">
      <th mat-header-cell *matHeaderCellDef mat-sort-header i18n>Name</th>
      <td mat-cell *matCellDef="let row">{{ row.title }}</td>
    </ng-container>


    <ng-container matColumnDef="lastScannedOn">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>lastScannedOn</th>
      <td mat-cell *matCellDef="let row">{{ row.lastScannedOn | date: 'dd MMM yy' }}</td>
    </ng-container>

    <ng-container matColumnDef="totalScanned">
      <th mat-header-cell *matHeaderCellDef mat-sort-header i18n>totalScanned</th>
      <td mat-cell *matCellDef="let row">{{ row.totalScanned }}</td>
    </ng-container>

    <ng-container matColumnDef="publishState">
      <th mat-header-cell *matHeaderCellDef mat-sort-header="wasPublished" i18n>publishState</th>
      <td mat-cell *matCellDef="let row">{{ translatePublished(row.publishState) }}</td>
    </ng-container>

    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
  </table>
  <mat-paginator [pageSizeOptions]="[25, 50, 100, 250]"></mat-paginator>
  </div>




but now I get this error:

ERROR TypeError: Cannot set property 'sort' of undefined
    at EcheqQrcodeComponent.push../src/app/components/echeq-qrcode/echeq-qrcode.component.ts.EcheqQrcodeComponent.ngOnInit (echeq-qrcode.component.ts:66)
    at checkAndUpdateDirectiveInline (core.js:18620)
    at checkAndUpdateNodeInline (core.js:19884)
    at checkAndUpdateNode (core.js:19846)
    at debugCheckAndUpdateNode (core.js:20480)
    at debugCheckDirectivesFn (core.js:20440)
    at Object.eval [as updateDirectives] (EcheqQrcodeComponent_Host.ngfactory.js?

That sorting will work for every column.

Thank you

and if I do this:

 ngOnInit() {

    this.qrCodeDefintion.getQRCodeList(1, this.patientId).subscribe((subs) => {
    (this.source = subs);
    });

    if (this.data && this.data.definition) {
      this.source = this.data.definition;
    }
    // this.datasource.paginator = this.paginator;
    this.datasource = new MatTableDataSource<QRCodeDefinitionInfoApi>();
    this.datasource.sort = this.sort;
  }

I dont get an error. But sorting doesnt work at all

My ngOnit looks now like this:

ngOnInit() {

    this.qrCodeDefintion.getQRCodeList(1, this.patientId).subscribe((subs) => {
    (this.source = subs);


    });

    if (this.data && this.data.definition) {
      this.datasource = new MatTableDataSource<QRCodeDefinitionInfoApi>(this.source);
      this.datasource.sort = this.sort;
      this.datasource.paginator = this.paginator;
      this.source = this.data.definition;
    }
    // this.datasource.paginator = this.paginator;



  }

But if I do this:

 <div class="mat-elevation-z8">
    <table
      mat-table
      class="full-width-table"
      [dataSource]="datasource"
      matSort
      aria-label="Elements"
    >

Then the data is not visible anymore.

Thank you. But if I do that. I get this error:

Yes, thank you. But now I get this error: this.source =

this.data.definition;

core.js:12584 ERROR TypeError: Cannot read property 'definition' of undefined
    at SafeSubscriber._next (echeq-qrcode.component.ts:61)
    at SafeSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.SafeSubscriber.__tryOrUnsub (Subscriber.js:196)

This is how I have it now:

ngOnInit() {

    this.qrCodeDefintion.getQRCodeList(1, this.patientId).subscribe((subs) => {
      (this.source = subs);
        this.datasource = new MatTableDataSource<QRCodeDefinitionInfoApi>(this.source);
        this.datasource.sort = this.sort;
        this.datasource.paginator = this.paginator;
        this.source = this.data.definition;

      });
  }

And this is the html file:

<div class="header">
    <h1 class="heading page-heading patient-list-heading">Scanned QR Codes </h1>
  <div class="qrcode-menu">
  </div>
</div>

  <div class="mat-elevation-z8">
    <table
      mat-table
      class="full-width-table"
      [dataSource]="source"
      matSort
      aria-label="Elements"
    >
    <ng-container matColumnDef="title">
      <th mat-header-cell *matHeaderCellDef mat-sort-header i18n>Name</th>
      <td mat-cell *matCellDef="let row">{{ row.title }}</td>
    </ng-container>


    <ng-container matColumnDef="lastScannedOn">
      <th mat-header-cell *matHeaderCellDef mat-sort-header>lastScannedOn</th>
      <td mat-cell *matCellDef="let row">{{ row.lastScannedOn | date: 'dd MMM yy' }}</td>
    </ng-container>

    <ng-container matColumnDef="totalScanned">
      <th mat-header-cell *matHeaderCellDef mat-sort-header i18n>totalScanned</th>
      <td mat-cell *matCellDef="let row">{{ row.totalScanned }}</td>
    </ng-container>

    <ng-container matColumnDef="publishState">
      <th mat-header-cell *matHeaderCellDef mat-sort-header="wasPublished" i18n>publishState</th>
      <td mat-cell *matCellDef="let row">{{ translatePublished(row.publishState) }}</td>
    </ng-container>

    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
  </table>
  <mat-paginator [pageSizeOptions]="[25, 50, 100, 250]"></mat-paginator>
  </div>

I also tried this:

ngAfterViewInit () {

    this.qrCodeDefintion.getQRCodeList(1, this.patientId).subscribe((subs) => {
      (this.source = subs);
    this.datasource = new MatTableDataSource<QRCodeDefinitionInfoApi>(this.source);
    setTimeout(() => {
      this.datasource.sort = this.sort;
      this.datasource.paginator = this.paginator;

    });
  });

Dont get any errors.But sorting doesnt work.

And if I do a console.log(this.datasource.sort) in the ngAfterViewInit(){}

then I see this:

MatSort {_disabled: false, _isInitialized: true, _pendingSubscribers: null, initialized: Observable, sortables: Map(4), …}
direction: (...)
disableClear: (...)
disabled: (...)
initialized: Observable {_isScalar: false, _subscribe: ƒ}
sortChange: EventEmitter
closed: false
hasError: false
isStopped: false
observers: (5) [Subscriber, Subscriber, Subscriber, Subscriber, Subscriber]
thrownError: null
__isAsync: false
_isScalar: false
__proto__: Subject
sortables: Map(4)
size: (...)
__proto__: Map
[[Entries]]: Array(4)
0: {"title" => MatSortHeader}
key: "title"
value: MatSortHeader {_disabled: false, _intl: MatSortHeaderIntl, _sort: MatSort, _columnDef: MatColumnDef, _showIndicatorHint: false, …}
1: {"lastScannedOn" => MatSortHeader}
2: {"totalScanned" => MatSortHeader}
3: {"wasPublished" => MatSortHeader}
length: 4
start: "asc"
_direction: ""
_disabled: false
_isInitialized: true
_pendingSubscribers: null
_stateChanges: Subject {_isScalar: false, observers: Array(4), closed: false, isStopped: false, hasError: false, …}
__proto__: class_1

So it seems that this is correctly. Isnt?

if I do this:

  sortData(sort: Sort)     {
       this.datasource.sort = this.sort;
       console.log(this.datasource.sort);
      }

I see this:

MatSort {_disabled: false, _isInitialized: true, _pendingSubscribers: null, initialized: Observable, sortables: Map(4), …}
active: "totalScanned"
direction: (...)
disableClear: (...)
disabled: (...)
initialized: Observable {_isScalar: false, _subscribe: ƒ}
sortChange: EventEmitter {_isScalar: false, observers: Array(6), closed: false, isStopped: false, hasError: false, …}
sortables: Map(4) {"title" => MatSortHeader, "lastScannedOn" => MatSortHeader, "totalScanned" => MatSortHeader, "wasPublished" => MatSortHeader}
start: "asc"
_direction: "desc"
_disabled: false
_isInitialized: true
_pendingSubscribers: null
_stateChanges: Subject {_isScalar: false, observers: Array(4), closed: false, isStopped: false, hasError: false, …}
__proto__: class_1

Upvotes: 4

Views: 18087

Answers (2)

Devesh G
Devesh G

Reputation: 129

In your html file add the below code<table mat-table [dataSource]="listData" matSort (matSortChange)="sortData($event)" >

In ng container add below code <th mat-header-cell *matHeaderCellDef mat-sort-header >Display

In your .ts (typescript code) add the below function as it: sortData(sort: Sort) { this.listData.sort = this.sort; }

This should fix your sorting issue.

Upvotes: 1

Kinjal
Kinjal

Reputation: 680

You have to change this.datasource = new MatTableDataSource<QRCodeDefinitionInfoApi>();

with this.datasource = new MatTableDataSource<QRCodeDefinitionInfoApi>(this.source);

And in HTML you have to pass [dataSource]="datasource" instead of [dataSource]="source"

Edit:

can you please change your ngOnInit method like give below


ngOnInit() {

    this.qrCodeDefintion.getQRCodeList(1, this.patientId).subscribe((subs) => {
    (this.source = subs);
      this.datasource = new MatTableDataSource<QRCodeDefinitionInfoApi>(this.source);
      this.datasource.sort = this.sort;
      this.datasource.paginator = this.paginator;
      this.source = this.data.definition;

    });
    // this.datasource.paginator = this.paginator;



  }

Upvotes: 4

Related Questions