Angular matSort not working

2020-02-05 01:20发布

I'm having trouble with importing matSort into my matTable.

I'm providing you with my code:

dashboard.component.ts

import {Component, ViewChild} from '@angular/core';
import {UserService} from "../user.service";
import {DohvatMantisaService} from "../dohvat-mantisa.service";
import {Mantisi} from "../Mantisi";
import {Observable} from "rxjs/Observable";
import {DataSource} from "@angular/cdk/collections";
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import {MatSort} from '@angular/material';
@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent{
  displayedColumns = ['projekt', 'manits', 'kategorija','ozbiljnost','datum_prijave','postavio','odjel','postavio','naziv','status','planirana_isporuka'];
  constructor(private user:UserService, private dohvatMantisa:DohvatMantisaService) {
  }
  dataSource: TableDataSource | null;
  mantisi: Mantisi[];
  name = this.user.getUsername();
  @ViewChild(MatSort) sort: MatSort;
  ngOnInit() {
    this.dataSource = new TableDataSource(this.dohvatMantisa,this.sort);
  }
}

export class TableDataSource extends DataSource<Mantisi>{
  constructor(private mantisiDS: DohvatMantisaService,private sort: MatSort){
    super();
  }
  connect(): Observable<Mantisi[]> {
    const displayDataChanges = [
      this.mantisiDS.dohvatiMantise(),
      this.sort.sortChange,
    ];

    return Observable.merge(...displayDataChanges).map(() => {
      return this.getSortedData();
    });
  }
  disconnect() {}

  getSortedData(): Mantisi[]{
    const data = this.mantisiDS.prikazMantisa().slice();
    if (!this.sort.active || this.sort.direction == '') { return data; }
    return data.sort((a, b) => {
      let propertyA: number|string = '';
      let propertyB: number|string = '';
      switch (this.sort.active) {
        case 'projekt': [propertyA, propertyB] = [a.projekt, b.projekt]; break;
        case 'manits': [propertyA, propertyB] = [a.manits, b.manits]; break;
        case 'kategorija': [propertyA, propertyB] = [a.kategorija, b.kategorija]; break;
        case 'ozbiljnost': [propertyA, propertyB] = [a.ozbiljnost, b.ozbiljnost]; break;
        case 'datum_prijave': [propertyA, propertyB] = [a.datum_prijave, b.datum_prijave]; break;
        case 'postavio': [propertyA, propertyB] = [a.postavio, b.postavio]; break;
        case 'naziv': [propertyA, propertyB] = [a.naziv, b.naziv]; break;
        case 'status': [propertyA, propertyB] = [a.status, b.status]; break;
        case 'planirana_isporuka': [propertyA, propertyB] = [a.planirana_isporuka, b.planirana_isporuka]; break;
      }

      let valueA = isNaN(+propertyA) ? propertyA : +propertyA;
      let valueB = isNaN(+propertyB) ? propertyB : +propertyB;

      return (valueA < valueB ? -1 : 1) * (this.sort.direction == 'asc' ? 1 : -1);
    });
  }
}

This is my service: dohvatMantisaService

import { Injectable } from '@angular/core';
import {Http, Response, RequestOptions, Headers} from "@angular/http";
import {Observable} from "rxjs/Observable";
import {Mantisi} from "./Mantisi";
import 'rxjs';
import 'rxjs/operator/map';
import 'rxjs/operator/do';

@Injectable()
export class DohvatMantisaService {
  constructor(public http:Http) { }
  result: Mantisi[];
  dohvatiMantise(): Observable<Mantisi[]>{
    return this.http.get('/mantis/getMantisReport').map(this.extractData);
  }
  private extractData(response: Response) {
    let body = response.json();
    return body || {};
  }

  prikazMantisa(): Mantisi[]{
    this.dohvatiMantise().subscribe(res => this.result = res);
    return this.result;
  }
}

And im providing you with my dashboard.component.html matSort row:

<mat-table #table [dataSource]="dataSource" class="example-table" matSort>

The main problem here is that data is loaded and acquired from http request but I'm getting errors in console something like this:

Cannot read property 'sortChange' of undefined at TableDataSource.webpackJsonp.../../../../../src/app/dashboard/dashboard.component.ts.TableDataSource.connect (dashboard.component.ts:36) at MatTable.webpackJsonp.../../../cdk/esm5/table.es5.js.CdkTable._observeRenderChanges (table.es5.js:602) at MatTable.webpackJsonp.../../../cdk/esm5/table.es5.js.CdkTable.ngAfterContentChecked (table.es5.js:522)

It tells me that this.sort.sortChange is undefined. I searched all bit of internet and couldn't find proper answer. Hope you can help me with that.

8条回答
戒情不戒烟
2楼-- · 2020-02-05 01:53

I had the same issue and fixed it by adding below:

@ViewChild(MatSort) set matSort(ms: MatSort) {
this.sort = ms;
this.setDataSourceAttributes();
 }

@ViewChild(MatPaginator) set matPaginator(mp: MatPaginator) {
 this.paginator = mp;
this.setDataSourceAttributes();
 }

setDataSourceAttributes() {
  this.dataSource.paginator = this.paginator;
  this.dataSource.sort = this.sort;
  }
查看更多
啃猪蹄的小仙女
3楼-- · 2020-02-05 01:55

I've found solution for this problem.

The main problem was that table was rendered before data arrived. I've loaded data first and sent it like source to dataSource constructor. After it, problem disappeared. That's the thing with async http.get and services.

Thanks for you help.

fetchData(id){
  this.fetch.getProcesses(id).subscribe(result => {
    this.processes = result;
    this.dataSource = new TableDataSource(this.processes);
    Observable.fromEvent(this.filter.nativeElement, 'keyup')
      .debounceTime(150)
      .distinctUntilChanged()
      .subscribe(() => {
        if (!this.dataSource) {
          return;
        }
        this.dataSource.filter = this.filter.nativeElement.value;
      });
  });
}




export class TableDataSource extends DataSource<Proces>{
  _filterChange = new BehaviorSubject('');
  get filter(): string {
    return this._filterChange.value;
  }
  set filter(filter: string) {
    this._filterChange.next(filter);
  }
  filteredData: any =[];

  constructor(private processes:Proces[]){
    super();
  }
  connect(): Observable<Proces[]>{
    const displayDataChanges = [
      this.processes,
      this._filterChange,
    ];
    return Observable.merge(...displayDataChanges).map(() => {
      this.filteredData = this.processes.slice().filter((item: Proces) => {
        const searchStr = (item.name).toLowerCase();
        return searchStr.indexOf(this.filter.toLowerCase()) !== -1;

      });
      return this.filteredData;
    })
  }
  disconnect(){}
}



      <div class="header">
    <mat-form-field floatPlaceholder="never">
      <input matInput #filter placeholder="Pretraži procese">
    </mat-form-field>
  </div>
  <mat-table #table [dataSource]="dataSource" class="table-mantis" matSort>

    <ng-container matColumnDef="col1">
      <mat-header-cell *matHeaderCellDef class="table-header-cell" mat-sort-header> Name</mat-header-cell>
      <mat-cell *matCellDef="let row" class="example-cell" > {{row.nazivProcesa}} </mat-cell>
    </ng-container>

    <ng-container matColumnDef="col2">
      <mat-header-cell *matHeaderCellDef class="table-header-cell" mat-sort-header> Cell 2</mat-header-cell>
      <mat-cell *matCellDef="let row" class="example-cell" > {{row.nazivVlasnika
        }} </mat-cell>
    </ng-container>

    <ng-container matColumnDef="col3">
      <mat-header-cell *matHeaderCellDef class="table-header-cell" mat-sort-header> Cell 3</mat-header-cell>
      <mat-cell *matCellDef="let row" class="example-cell" > {{row.interniAkt}} </mat-cell>
    </ng-container>

    <mat-header-row *matHeaderRowDef="displayedColumns" class="example-header-row"></mat-header-row>
    <mat-row class="example-row" *matRowDef="let row; columns: displayedColumns;"></mat-row>
  </mat-table>
查看更多
何必那么认真
4楼-- · 2020-02-05 02:00

I had the same issue,

There are a couple of reasons for this issue

  1. Make sure you have included MatSortModule module in your App module
 import { MatSortModule, MatPaginatorModule, MatTableModule } from '@angular/material';

 @NgModule({
  imports: [MatSortModule, MatPaginatorModule, MatTableModule],
  exports: []
})
  1. Make sure you have subscribed sort change in the ngAfterViewInit
  ngAfterViewInit() {
    this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0 );
  }
查看更多
手持菜刀,她持情操
5楼-- · 2020-02-05 02:01

If you use "*ngIf" to initialy hide the table container in your template, the viewchield will be undefined.

查看更多
做个烂人
6楼-- · 2020-02-05 02:01

With Angular 8 and Material 6.4.1 if you waiting to receive a data from a service the simplest and best way to fix the MatSort and MatPaginator is to set the static: false instead of true, like this:

@ViewChild(MatSort, { static: false }) sort: MatSort;
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;

In my case is an ngOnChanges call for data.

查看更多
做个烂人
7楼-- · 2020-02-05 02:18

I just had this problem, and all I had to do was making sure you're referencing your matSort viewChild correctly and make sure you have added the MatSortModule in your module.ts file in the imports area.

Like the following: @NgModule({ imports: [ MatSortModule, MatTableModule, ] )}

查看更多
登录 后发表回答