Angular material table does not work when sort + @Input()

587 Views Asked by At

I´m doing a table component.

This component works perfectly without sortable functionnality. When I´m trying to make the table sortable, that works if I´m using basic example when you store the object list in a constant but rows do not display when I´m trying to use @Input()

Version with constant - That works

import {AfterContentInit, AfterViewInit, Component, Input, OnInit, ViewChild} from '@angular/core';
import {Client, ClientStatus} from '@models/client.model';
import {ClientService} from '@services/client.service';
import {MatSort, Sort} from '@angular/material/sort';
import {MatTableDataSource} from '@angular/material/table';

const ELEMENT_DATA: Client[] = [
 ...
];

@Component({
  selector: 'app-table-entries',
  templateUrl: './table-entries.component.html',
  styleUrls: ['./table-entries.component.scss']
})
export class TableEntriesComponent implements OnInit, AfterViewInit {
  displayedColumns: string[] = ['expectedDate', 'description.id', 'priority' ];
  @ViewChild(MatSort, {static: true}) sort: MatSort;
  sortableEntries = new MatTableDataSource(ELEMENT_DATA);

  constructor( clientService: ClientService ) {}
  ngOnInit(): void {}

  ngAfterViewInit() {
    this.sort.active = 'expectedDate';
    this.sort.direction = 'asc';
    this.sortableEntries.sort = this.sort;
    this.sortableEntries.sortingDataAccessor = ( client, property) => {
      switch ( property ) {
        case 'description.id': return client.description.id;
        default: return client[property];
      }
    };
  }
}

Version with @Input - That does not work

import {AfterContentInit, AfterViewInit, Component, Input, OnInit, ViewChild} from '@angular/core';
import {Client, ClientStatus} from '@models/client.model';
import {ClientService} from '@services/client.service';
import {MatSort, Sort} from '@angular/material/sort';
import {MatTableDataSource} from '@angular/material/table';

@Component({
  selector: 'app-table-entries',
  templateUrl: './table-entries.component.html',
  styleUrls: ['./table-entries.component.scss']
})
export class TableEntriesComponent implements OnInit, AfterViewInit {
  @Input() entries: Client[] = [];
  displayedColumns: string[] = ['expectedDate', 'description.id', 'priority' ];
  @ViewChild(MatSort, {static: true}) sort: MatSort;
  sortableEntries: MatTableDataSource<Client>;

  constructor( clientService: ClientService ) {}
  ngOnInit(): void {
      this.sortableEntries = new MatTableDataSource<Client>( this.entries );
  }

  ngAfterViewInit() {
    this.sort.active = 'expectedDate';
    this.sort.direction = 'asc';
    this.sortableEntries.sort = this.sort;
    this.sortableEntries.sortingDataAccessor = ( client, property) => {
      switch ( property ) {
        case 'description.id': return client.description.id;
        default: return client[property];
      }
    };
  }
}

Template

<table mat-table matSort [dataSource]="sortableEntries">
  <!-- Heure RDV -->
  <ng-container matColumnDef="expectedDate">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Heure rdv </th>
    <td mat-cell *matCellDef="let element"> {{ element.expectedDate | date: "d/M HH:mm" }} </td>
  </ng-container>

  <!-- Identifiant -->
  <ng-container matColumnDef="description.id">
    <th mat-header-cell *matHeaderCellDef mat-sort-header="description.id"> Identifiant </th>
    <td mat-cell *matCellDef="let element"> {{ element.description.id}} </td>
  </ng-container>

  <!-- Nature -->
  <ng-container matColumnDef="priority">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Nature </th>
    <td mat-cell *matCellDef="let element" > {{ element.priority | getStringPriority }} </td>
  </ng-container>

  <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
  <tr mat-row *matRowDef="let row; let even = even; columns: displayedColumns;" [ngClass]="{ 'table-even-row': even}"></tr>
</table>
<section *ngIf="entries && entries.length === 0" class="no-client-wrapper"><p>Il n'y a pas d'entrée actuellement</p></section>

I can imagine the problem is the moment when the object list is loaded but I don´t know how to fix this. Someone has got an idea ?

1

There are 1 best solutions below

0
On BEST ANSWER

I found a solution here.

First of all, change @Input() entries: Client[] = []; by

@Input() set entries( data: Client[] ) {
  this.setTableDataSource(data);
}

Then, Use the content in ngAfterViewInit to make the function

setTableDataSource(data: any) {
    this.sortableEntries = new MatTableDataSource<any>(data);
    this.sortableEntries.sort = this.sort;
    this.sort.active = 'expectedDate';
    this.sort.direction = 'asc';
    this.sortableEntries.sortingDataAccessor = ( client, property) => {
      switch ( property ) {
        case 'description.codeUT': return client.description.codeUT;
        default: return client[property];
      }
    };
  }

Complete result

import {AfterContentInit, AfterViewInit, Component, Input, OnInit, ViewChild} from '@angular/core';
import {Client, ClientStatus} from '@models/client.model';
import {ClientService} from '@services/client.service';
import {MatSort, Sort} from '@angular/material/sort';
import {MatTableDataSource} from '@angular/material/table';

@Component({
  selector: 'app-table-entries',
  templateUrl: './table-entries.component.html',
  styleUrls: ['./table-entries.component.scss']
})
export class TableEntriesComponent implements OnInit{
  displayedColumns: string[] = ['expectedDate', 'description.id', 'priority' ];
  @ViewChild(MatSort, {static: true}) sort: MatSort;
  sortableEntries: MatTableDataSource<Client>;

  @Input() set entries( data: Client[] ) {
    this.setTableDataSource(data);
  }

  setTableDataSource(data: any) {
    this.sortableEntries = new MatTableDataSource<any>(data);
    this.sortableEntries.sort = this.sort;
    this.sort.active = 'expectedDate';
    this.sort.direction = 'asc';
    this.sortableEntries.sortingDataAccessor = ( client, property) => {
      switch ( property ) {
        case 'description.id': return client.description.id;
        default: return client[property];
      }
    };
  }

  constructor( clientService: ClientService ) {
    this.sortableEntries = new MatTableDataSource<Client>( this.entries );
  }
  ngOnInit(): void {
    console.dir( this.entries );
  }

}