Estoy tratando de que la mat-table
clasificación funcione localmente, y aunque puedo hacer que los datos se muestren como se esperaba, hacer clic en la fila del encabezado no realiza la clasificación como lo hace en los ejemplos en línea (no sucede nada). Estoy tratando de que esta demostración funcione localmente:
https://material.angular.io/components/sort/overview
https://plnkr.co/edit/XF5VxOSEBxMTd9Yb3ZLA?p=preview
He generado un nuevo proyecto con Angular CLI, luego seguí estos pasos: https://material.angular.io/guide/getting-started
Aquí están mis archivos locales:
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 */
¿Alguien tiene una idea de por qué aparecería como la tabla en línea pero carece de la funcionalidad de clasificación?
fuente
ng test --sm=false
y vea lo que sale.Respuestas:
Para cualquier otra persona que pueda tener este problema: El problema fue que no leí correctamente la referencia de API en el sitio web de materiales angulares, la parte que decía que tenía que importar MatSortModule. Después de cambiar mi lista de importaciones en app.module.ts a
funcionó bien
fuente
BrowserAnimationsModule
también se importa en app.module.tsMatSortModule
yBrowserAnimationsModule
, y me he asegurado de que el valor de matColumnDef coincida con el nombre de la propiedad, pero todavía no puedo hacer nada.Tuve un problema de que la función de clasificación estaba funcionando pero no estaba clasificando correctamente. Me di cuenta de que
matColumnDef
tiene que tener el mismo nombre de la propiedad de miclass / interface
referencia en la que estoy haciendo referenciamatCellDef
.Según la documentación de Angular Material :
Por ejemplo:
El contenido
name
de lamatColumnDef
directiva debe ser el mismo que elname
utilizado en el<mat-cell>
componente.fuente
element
, como este `{{row.getName ()}}`Si la tabla está dentro de * ngIf, no funcionará. Funcionará si se cambia a [oculto]
fuente
<div *ngIf="xxx">
la<div [hidden]="!xxx">
El nombre de matColumnDef y el nombre del valor real * matCellDef deben ser iguales
Ejemplo:
En mi caso, oppNo es el mismo para el nombre matColumnDef y el nombre * matCellDef y la clasificación funciona bien.
fuente
Agregar ordenamiento dentro del bloque de tiempo de espera funciona para mí,
Si no quiere usar ganchos de vida.
fuente
También toqué este tema. Dado que debe esperar a que se defina el niño, debe implementar y usar
AfterViewInit
, no onInit.fuente
ngAfterViewInit
? El resto estaba trabajando desdengOnInit
. Es solo para tratar de entender, se solucionó gracias a tiPasé horas en este tema. Después de leer varios hilos, estos son los pasos que seguí.
MatSortModule
.*ngIf
. Cambiarlo a[hidden]
como @zerg recomienda . (No entiendo por qué)Espero que esto ayude.
fuente
Mi solución fue arreglar varias cosas (básicamente fusionando la mayoría de las soluciones en esta página).
Cosas para comprobar:
BrowserModule, MatTableModule, MatSortModule
Los módulos deben importarse en el archivo de módulos raíz.MatTableDatasource
clase y pasar su matriz de datos como parámetro*ngIf=....
directiva. En su lugar, use otras operaciones condicionales (todavía no entiendo por qué).fuente
Para mí, reemplazar * ngIf con el atributo [oculto] para la etiqueta mat-table funcionó. ¿Cómo publicar este como un error en la comunidad de Angular Material?
fuente
Arreglé esto en mi escenario al nombrar los datos de la tabla con el mismo nombre que * matColumnDef Por ejemplo:
En lugar
fuente
Hubo 2 problemas para mí.
Estaba obteniendo los datos del servicio. La ordenación ngOnInit no funcionaba. Reemplazadas con
ngAfterViewInit () {this.dataSource.sort = this.sort; }
fuente
Encontré este viejo blog que me ayudó a que funcionara: https://www.jeffryhouser.com/index.cfm/2018/10/23/Five-Reasons-My-ngMaterial-Table-wont-sort
MatSortModule
matSort
encabezadoMatTableDataSource
<table mat-table [dataSource]="this.products" matSort>
) pero debería haber usado el objeto de fuente de datos que inicialicé en el código (<table mat-table [dataSource]="this.dataSource" matSort>
). La fuente de datos se inicializa comodataSource = new MatTableDataSource(this.products)
ngOnInit
/ngAfterViewInit
MatTableDataSource
fuente
Si su tabla está dentro de un * ngIf y cree que tiene algo que ver con que no clasifique su tabla, entonces especificar su propia
sortingDataAccessor
función podría resolver el problema como lo hizo para mí. Tengo mi tabla dentro de un par de * ngIfs y sacarla de esos * ngIfs no tenía sentido:fuente
Una de las razones por las que MatSort podría no funcionar es cuando se agrega a una fuente de datos (es decir
this.dataSource.sort = this.sort
) antes de que se defina. Puede haber varias razones para esto:si agrega la ordenación en ngOnInit. En este punto, la plantilla aún no está renderizada, por lo que el MatSort con el que obtiene
@ViewChild(MatSort, { static: true }) sort: MatSort;
no está definido y, comprensiblemente, no hará nada. Una solución para este problema es pasarthis.dataSource.sort = sort
a ngAfterViewInit. Cuando se llama a ngAfterViewInit, su componente se representa y se debe definir MatSort.cuando usa * ngIf es su plantilla en el elemento de su tabla o una si son elementos principales y este * ngIf hace que su tabla no se muestre en el momento en que intenta establecer MatSort. Por ejemplo, si tiene
*ngIf="dataSource.data.length > 0"
en su elemento de tabla (para representarlo solo si hay datos presentes) y lo establecethis.dataSource.sort = this.sort
justo después de establecerthis.dataSource.data
con sus datos. La vista del componente no se volverá a generar todavía, por lo que MatSort seguirá sin estar definido.Para que MatSort funcione y aún muestre condicionalmente su tabla, puede decidir reemplazar el
*ngIf
con[hidden]
como se indica en muchas otras respuestas. Sin embargo, si desea mantener su declaración * ngIf, puede usar la siguiente solución. Esta solución funciona para Angular 9, no la he probado en versiones anteriores, así que no estoy seguro de si funciona allí.Encontré esta solución aquí: https://github.com/angular/components/issues/10205
En lugar de poner:
use un setter para matSort. Este setter se activará una vez que matSort en su vista cambie (es decir, se defina la primera vez), no se activará cuando cambie su clasificación haciendo clic en las flechas. Esto se verá así:
Si tiene otras funciones que (programáticamente) cambian la clasificación, no estoy seguro de si se activará nuevamente, no lo he probado. Si desea asegurarse de que solo establece el tipo si el tipo no estaba definido, puede hacer algo como esto:
fuente
Vea si tiene algún error de JavaScript en la consola. Podría ser que alguna otra cosa fallara antes de que se inicializara la clasificación.
fuente