J'essaie de faire fonctionner le mat-table
tri localement, et bien que je puisse faire apparaître les données comme prévu, cliquer sur la ligne d'en-tête ne fait pas le tri comme sur 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-sorting-example.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-sorting-example.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 apparaîtrait comme le tableau en ligne mais ne dispose pas de la fonctionnalité de tri?
la source
ng test --sm=false
et voyez ce qui sort.Réponses:
Pour tous ceux qui pourraient avoir ce problème: Le problème était que je n'avais pas lu correctement la référence API sur le site Web des matériaux angulaires, la partie qui disait que je devais importer MatSortModule. Après avoir changé ma liste d'importations dans app.module.ts en
ça a bien fonctionné
la source
BrowserAnimationsModule
est également importé dans app.module.tsMatSortModule
etBrowserAnimationsModule
, et je me suis assuré que la valeur matColumnDef correspond au nom de la propriété, mais je suis toujours incapable de faire quoi que ce soit.J'ai eu un problème car la fonction de tri fonctionnait mais elle ne triait pas correctement. J'ai réalisé que
matColumnDef
doit avoir le même nom de la propriété de monclass / interface
auquel je fais référencematCellDef
.Selon la documentation du matériau angulaire :
Par exemple:
Le
name
dans lamatColumnDef
directive doit être le même que celuiname
utilisé dans le<mat-cell>
composant.la source
element
, comme celle-ci `{{row.getName ()}}`Si la table est à l'intérieur de * ngIf, cela ne fonctionnera pas. Cela fonctionnera s'il est remplacé par [masqué]
la source
<div *ngIf="xxx">
la<div [hidden]="!xxx">
Le nom matColumnDef et le nom de la valeur réelle * matCellDef doivent être identiques
Exemple:
Dans mon cas, oppNo est le même pour le nom matColumnDef et le nom * matCellDef et le tri fonctionne bien.
la source
L'ajout de tri dans le bloc de délai d'expiration fonctionne pour moi,
Si vous ne souhaitez pas utiliser de hooks de cycle de vie.
la source
J'ai également touché ce problème. Puisque vous devez attendre que l'enfant soit défini, vous devez implémenter et utiliser
AfterViewInit
, pas onInit.la source
ngAfterViewInit
? Le reste travaillait à partir dengOnInit
. C'est juste pour essayer de comprendre, c'est réparé grâce à vousJ'ai passé des heures sur cette question. Après avoir lu un certain nombre de fils, voici les étapes que j'ai suivies.
MatSortModule
.*ngIf
. Remplacez-le[hidden]
par @zerg recommandé . (Je ne comprends pas pourquoi)J'espère que cela t'aides.
la source
Ma solution était de corriger plusieurs choses (en gros en fusionnant la plupart des solutions de cette page).
Choses à vérifier:
BrowserModule, MatTableModule, MatSortModule
Les modules doivent être importés dans le fichier des modules racine.MatTableDatasource
classe et passez votre tableau de données en tant que paramètre*ngIf=....
directive. Utilisez à la place d'autres opérations conditionnelles (vous ne comprenez toujours pas pourquoi).la source
Pour moi, remplacer * ngIf par l'attribut [hidden] pour la balise mat-table a fonctionné. Comment publier celui-ci comme un bogue dans la communauté Angular Material?
la source
J'ai corrigé cela dans mon scénario en nommant les données de la table avec le même nom que * matColumnDef Par exemple:
Au lieu
la source
Il y avait 2 problèmes pour moi.
J'obtenais les données du service. Le tri ngOnInit ne fonctionnait pas. Remplacé par
ngAfterViewInit () {this.dataSource.sort = this.sort; }
la source
J'ai trouvé cet ancien blog qui m'a aidé à le faire fonctionner: https://www.jeffryhouser.com/index.cfm/2018/10/23/Five-Reasons-My-ngMaterial-Table-wont-sort
MatSortModule
matSort
têteMatTableDataSource
<table mat-table [dataSource]="this.products" matSort>
) mais j'aurais dû utiliser l'objet de source de données que j'ai initialisé dans le code (<table mat-table [dataSource]="this.dataSource" matSort>
). La source de données est initialisée commedataSource = new MatTableDataSource(this.products)
ngOnInit
/ngAfterViewInit
MatTableDataSource
la source
Si votre table est à l'intérieur d'un * ngIf et que vous pensez que cela a quelque chose à voir avec le fait que vous ne triez pas votre table, alors la spécification de votre propre
sortingDataAccessor
fonction pourrait résoudre le problème comme cela a été le cas pour moi. J'ai ma table dans quelques * ngIfs et la retirer de ces * ngIfs n'avait pas de sens:la source
L'une des raisons pour lesquelles MatSort peut ne pas fonctionner est lorsqu'il est ajouté à une source de données (c'est-à-dire
this.dataSource.sort = this.sort
) avant qu'il ne soit défini. Il peut y avoir plusieurs raisons à cela:si vous ajoutez le tri dans ngOnInit. À ce stade, le modèle n'est pas encore rendu, donc le MatSort que vous obtenez
@ViewChild(MatSort, { static: true }) sort: MatSort;
n'est pas défini et ne fera naturellement rien. Une solution à ce problème consiste à passerthis.dataSource.sort = sort
à ngAfterViewInit. Lorsque ngAfterViewInit est appelé, votre composant est rendu et MatSort doit être défini.lorsque vous utilisez * ngIf est votre modèle sur votre élément de table ou un s'il s'agit d'éléments parents et que * ngIf empêche le rendu de votre table au moment où vous essayez de définir MatSort. Par exemple, si vous avez
*ngIf="dataSource.data.length > 0"
sur votre élément de table (pour le rendre uniquement s'il y a des données présentes) et que vous définissezthis.dataSource.sort = this.sort
juste après avoir définithis.dataSource.data
avec vos données. La vue du composant ne sera pas encore rendue, donc MatSort sera toujours indéfini.Afin de faire fonctionner MatSort tout en affichant conditionnellement votre table, vous pouvez décider de remplacer le
*ngIf
par[hidden]
comme indiqué dans plusieurs autres réponses. Cependant, si vous souhaitez conserver votre instruction * ngIf, vous pouvez utiliser la solution suivante. Cette solution fonctionne pour Angular 9, je ne l'ai pas testée sur les versions précédentes donc je ne suis pas sûr que cela fonctionne là-bas.J'ai trouvé cette solution ici: https://github.com/angular/components/issues/10205
Au lieu de mettre:
utilisez un setter pour matSort. Ce setter se déclenchera une fois que matSort dans votre vue change (c'est-à-dire qu'il est défini la première fois), il ne se déclenchera pas lorsque vous modifierez votre tri en cliquant sur les flèches. Cela ressemblera à ceci:
Si vous avez d'autres fonctions qui modifient (par programme) le tri, je ne suis pas sûr qu'il se déclenchera à nouveau, je n'ai pas testé cela. Si vous ne voulez pas vous assurer qu'il définit le tri uniquement si le tri n'était pas défini, vous pouvez faire quelque chose comme ceci:
la source
Voyez si vous avez des erreurs javascript dans la console. Il se peut qu'une autre chose ait échoué avant l'initialisation de votre tri.
la source