136 votes

La démo de tri de Mat-table ne fonctionne pas

J'essaie d'obtenir le mat-table J'essaie de faire en sorte que le triage fonctionne localement, et bien que je puisse faire en sorte que les données s'affichent comme prévu, le fait de cliquer sur la ligne d'en-tête n'effectue pas le triage comme dans les exemples en ligne (rien ne se passe du tout). J'essaie de faire fonctionner cette démo localement : https://material.angular.io/components/sort/overview https://plnkr.co/edit/XF5VxOSEBxMTd9Yb3ZLA?p=preview

J'ai généré un nouveau projet avec Angular CLI, puis j'ai suivi ces étapes : https://material.angular.io/guide/getting-started

Voici mes fichiers locaux :

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { MatSort, MatTableModule } from '@angular/material';

import { AppComponent } from './app.component';
import { TableSortingExample } from './table-sorting-example';

@NgModule({
  declarations: [
    AppComponent,
    TableSortingExample,
    MatSort
  ],
  imports: [
    BrowserModule,
    MatTableModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';
}

app.component.html

<div style="text-align:center">
  <h1>
    Welcome to {{title}}!
  </h1>
  <table-sorting-example></table-sorting-example>
</div>

table-tri-exemple.html

<div class="example-container mat-elevation-z8">
  <mat-table #table [dataSource]="dataSource" matSort>

    <!--- Note that these columns can be defined in any order.
          The actual rendered columns are set as a property on the row definition" -->

    <!-- ID Column -->
    <ng-container matColumnDef="userId">
      <mat-header-cell *matHeaderCellDef mat-sort-header> ID </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.id}} </mat-cell>
    </ng-container>

    <!-- Progress Column -->
    <ng-container matColumnDef="progress">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Progress </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.progress}}% </mat-cell>
    </ng-container>

    <!-- Name Column -->
    <ng-container matColumnDef="userName">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
    </ng-container>

    <!-- Color Column -->
    <ng-container matColumnDef="color">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Color </mat-header-cell>
      <mat-cell *matCellDef="let row" [style.color]="row.color"> {{row.color}} </mat-cell>
    </ng-container>

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

<!-- Copyright 2017 Google Inc. All Rights Reserved.
    Use of this source code is governed by an MIT-style license that
    can be found in the LICENSE file at http://angular.io/license -->

table-tri-exemple.ts

import {Component, ViewChild} from '@angular/core';
import {DataSource} from '@angular/cdk/collections';
import {MatSort} from '@angular/material';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/map';

/**
 * @title Table with sorting
 */
@Component({
  selector: 'table-sorting-example',
  styleUrls: ['table-sorting-example.css'],
  templateUrl: 'table-sorting-example.html',
})
export class TableSortingExample {
  displayedColumns = ['userId', 'userName', 'progress', 'color'];
  exampleDatabase = new ExampleDatabase();
  dataSource: ExampleDataSource | null;

  @ViewChild(MatSort) sort: MatSort;

  ngOnInit() {
    this.dataSource = new ExampleDataSource(this.exampleDatabase, this.sort);
  }
}

/** Constants used to fill up our data base. */
const COLORS = ['maroon', 'red', 'orange', 'yellow', 'olive', 'green', 'purple',
  'fuchsia', 'lime', 'teal', 'aqua', 'blue', 'navy', 'black', 'gray'];
const NAMES = ['Maia', 'Asher', 'Olivia', 'Atticus', 'Amelia', 'Jack',
  'Charlotte', 'Theodore', 'Isla', 'Oliver', 'Isabella', 'Jasper',
  'Cora', 'Levi', 'Violet', 'Arthur', 'Mia', 'Thomas', 'Elizabeth'];

export interface UserData {
  id: string;
  name: string;
  progress: string;
  color: string;
}

/** An example database that the data source uses to retrieve data for the table. */
export class ExampleDatabase {
  /** Stream that emits whenever the data has been modified. */
  dataChange: BehaviorSubject<UserData[]> = new BehaviorSubject<UserData[]>([]);
  get data(): UserData[] { return this.dataChange.value; }

  constructor() {
    // Fill up the database with 100 users.
    for (let i = 0; i < 100; i++) { this.addUser(); }
  }

  /** Adds a new user to the database. */
  addUser() {
    const copiedData = this.data.slice();
    copiedData.push(this.createNewUser());
    this.dataChange.next(copiedData);
  }

  /** Builds and returns a new User. */
  private createNewUser() {
    const name =
      NAMES[Math.round(Math.random() * (NAMES.length - 1))] + ' ' +
      NAMES[Math.round(Math.random() * (NAMES.length - 1))].charAt(0) + '.';

    return {
      id: (this.data.length + 1).toString(),
      name: name,
      progress: Math.round(Math.random() * 100).toString(),
      color: COLORS[Math.round(Math.random() * (COLORS.length - 1))]
    };
  }
}

/**
 * Data source to provide what data should be rendered in the table. Note that the data source
 * can retrieve its data in any way. In this case, the data source is provided a reference
 * to a common data base, ExampleDatabase. It is not the data source's responsibility to manage
 * the underlying data. Instead, it only needs to take the data and send the table exactly what
 * should be rendered.
 */
export class ExampleDataSource extends DataSource<any> {
  constructor(private _exampleDatabase: ExampleDatabase, private _sort: MatSort) {
    super();
  }

  /** Connect function called by the table to retrieve one stream containing the data to render. */
  connect(): Observable<UserData[]> {
    const displayDataChanges = [
      this._exampleDatabase.dataChange,
      this._sort.sortChange,
    ];

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

  disconnect() {}

  /** Returns a sorted copy of the database data. */
  getSortedData(): UserData[] {
    const data = this._exampleDatabase.data.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 'userId': [propertyA, propertyB] = [a.id, b.id]; break;
        case 'userName': [propertyA, propertyB] = [a.name, b.name]; break;
        case 'progress': [propertyA, propertyB] = [a.progress, b.progress]; break;
        case 'color': [propertyA, propertyB] = [a.color, b.color]; break;
      }

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

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

/**  Copyright 2017 Google Inc. All Rights Reserved.
 Use of this source code is governed by an MIT-style license that
 can be found in the LICENSE file at http://angular.io/license */

Quelqu'un a-t-il une idée de la raison pour laquelle il s'affiche comme le tableau en ligne mais ne dispose pas de la fonctionnalité de tri ?

0 votes

Je commencerais par déboguer l'application. Des erreurs ? Exécutez la commande ng test --sm=false et voir ce qui en est sorti.

0 votes

Cela fonctionne pour moi sans @ViewChild(MatSort) sort : MatSort ; Une raison ?

243voto

avern Points 1978

Pour tous ceux qui pourraient avoir ce problème : Le problème est que je n'ai pas lu correctement la référence API sur le site angular materials, la partie qui disait que je devais importer MatSortModule. Après avoir modifié la liste de mes importations dans app.module.ts à

imports: [
    BrowserModule,
    MatTableModule,
    MatSortModule
  ],

ça a bien marché

52 votes

Il n'y a aucune mention de ce module dans la documentation. material.angular.io/components/table/overview#sorting J'ai perdu une heure sur ça aussi.

1 votes

@SonicSoul vous avez raison, par lire l'API correctement je voulais dire regarder l'API du module de tri ( material.angular.io/components/sort/api ). Je suis d'accord sur le fait que cela devrait être noté sur l'aperçu de la table également.

12 votes

C'est bien, dans l'en-tête le texte est cliquable et l'icône est aussi là mais le tri ne fonctionne toujours pas.

180voto

Andre Evangelista Points 907

J'avais un problème : la fonction de tri fonctionnait, mais elle ne triait pas correctement. Je me suis rendu compte que matColumnDef doit avoir le même nom que la propriété de mon class / interface que je référence dans matCellDef .

Selon le matériau angulaire documentation :

Par défaut, le MatTableDataSource trie en supposant que le nom de la colonne triée correspond au nom de la propriété de données que la colonne affiche.

Par exemple :

<ng-container matColumnDef="name"> 
    <mat-header-cell *matHeaderCellDef mat-sort-header> NAME </mat-header-cell>
    <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
</ng-container>

Le site name dans le matColumnDef doit être identique à la directive name utilisé dans le <mat-cell> composant.

1 votes

À quoi faites-vous référence dans votre exemple ? Il serait utile de voir également votre interface, à des fins de comparaison.

2 votes

J'utilisais "Id" comme nom de colonne alors que l'entité avait "id". La différence de cas faisait qu'il ne s'exécutait pas (en raison d'une erreur de refactoring) . Maintenant c'est résolu. Merci

3 votes

@NitinSingh, que se passe-t-il si vous avez besoin d'appeler une fonction sur le fichier element comme ceci : {{row.getName()}} `

160voto

zerg Points 69

Si le tableau est à l'intérieur de *ngIf, il ne fonctionnera pas. Il fonctionnera s'il est changé en [hidden].

51 votes

VOUS M'AVEZ SAUVÉ LA MISE ! !! Utiliser à la place de <div *ngIf="xxx"> le site <div [hidden]="!xxx">

3 votes

Ou simplement définir la source de données dans ngAfterViewInit au lieu de ngOnInit.

2 votes

C'est le problème le plus "caché" qui puisse se produire, merci pour la solution ! Les documentations auraient pu prévenir de ce problème.

43voto

Siddu Points 171

Le nom de matColumnDef et le nom de la valeur réelle de *matCellDef doivent être identiques.

Exemple :

<ng-container matColumnDef="oppNo">
    <th mat-header-cell *matHeaderCellDef mat-sort-header>Opportunity Number</th>
    <td mat-cell *matCellDef="let element">{{element.oppNo}}</td>
</ng-container>

Dans mon cas, oppNo est le même pour le nom de matColumnDef et le nom de *matCellDef et le tri fonctionne bien.

0 votes

Intéressant. C'était aussi le cas pour moi. Mais, connaissez-vous le raisonnement réel derrière cela ou est-ce une sorte de "bug" ?

0 votes

J'ai découvert que la raison est qu'il prend cette clé dans le dataSource pour trier. Donc, il n'est pas nécessaire que ce soit 1to1 comme matCellDef, mais vous avez besoin d'une propriété de référence dans dataSource.

26voto

Chandrahasan Points 728

L'ajout du tri dans le bloc de délai d'attente fonctionne pour moi,

dataSource = new MatTableDataSource(this.articleService.getAllArticles());
setTimeout(() => {
  this.tableDataSource.sort = this.sort;
  this.tableDataSource.paginator = this.paginator;
});

Si vous ne voulez pas utiliser les crochets de lifecykle.

1 votes

Hack stupide mais ça marche, une idée de pourquoi ça ne marche pas sans le timeout ?

6 votes

C'est vraiment une mauvaise façon de faire. Cela fonctionne parce que vous laissez passer un certain temps après l'initialisation du composant pour que la source de données soit construite, et ensuite vous ajoutez le tri et le paginateur. Le mieux est de déplacer la construction de la source de données dans ngOnInit puis de déplacer les attributions de tri et de pagination dans AfterViewInit. C'est pour cela que les crochets de cycle de vie existent.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X