Угловой коврик не работает
У меня проблемы с импортом matSort в мой matTable.
Я предоставляю вам мой код:
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);
});
}
}
Это мой сервис: дохватМантизаСервис
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;
}
}
И я предоставляю вам мою строку dashboard.component.html matSort:
<mat-table #table [dataSource]="dataSource" class="example-table" matSort>
Основная проблема здесь в том, что данные загружаются и получаются из http-запроса, но я получаю ошибки в консоли примерно так:
Не удается прочитать свойство 'sortChange' из неопределенного в TableDataSource.webpackJsonp.../../../../../src/app/dashboard/dashboard.component.ts.TableDataSource.connect (dashboard.component.ts:36) в MatTable.webpackJsonp.../../../cdk/esm5/table.es5.js.CdkTable._observeRenderChanges (table.es5.js:602) в MatTable.webpackJsonp.../../../cdk/esm5/table.es5.js.CdkTable.ngAfterContentChecked (table.es5.js:522)
Это говорит мне, что this.sort.sortChange не определен. Я искал всю часть интернета и не мог найти правильный ответ. Надеюсь, вы можете помочь мне с этим.
14 ответов
Я нашел решение этой проблемы.
Основная проблема заключалась в том, что таблица отображалась до поступления данных. Сначала я загрузил данные и отправил их как источник в конструктор dataSource. После этого проблема исчезла. В том-то и дело с асинхронным http.get и сервисами.
Спасибо за помощь.
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>
Если вы используете "*ngIf" для первоначального скрытия контейнера таблицы в вашем шаблоне, окно обзора будет неопределенным.
У меня просто была эта проблема, и все, что мне нужно было сделать, это убедиться, что вы ссылаетесь на свой matSort viewChild
правильно и убедитесь, что вы добавили MatSortModule
в вашем файле module.ts в области импорта.
Как следующее:
@NgModule({
imports: [
MatSortModule,
MatTableModule,
]
)}
У меня была та же проблема, и я исправил ее, добавив ниже:
@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;
}
В Angular 8 и Material 6.4.1, если вы ждете получения данных от службы, самый простой и лучший способ исправить MatSort и MatPaginator - это установить static: false вместо true, например:
@ViewChild(MatSort, { static: false }) sort: MatSort;
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;
В моем случае это вызов данных ngOnChanges.
Итак, это происходит из-за того, что ваш метод this.sort.sortChange вызывается до того, как ваш дочерний вид Initialize
Вам просто нужно реализовать свой класс из AfterViewInit вместо OnInit
И используйте метод жизненного цикла ngAfterViewInit
export class ApplicantListComponent implements AfterViewInit {
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;
@ViewChild(MatSort, { static: false }) sort: MatSort;
constructor() {}
ngAfterViewInit() {
this.sort.sortChange.subscribe(() => {
this.paginator.pageIndex = 0;
this.paginator.pageSize = this.pageSize;
});
}
У меня была аналогичная проблема при передаче асинхронных данных с уровня контейнера на уровень компонентов. Вот мое решение
Поскольку элемент начинался без данных, нет смысла помещать конструктор или OnInit, как в исходном примере. Только после того, как поток данных поступает (асинхронно), я реализую сортировку и пагинатор в сеттере, и все сработало отлично.
В моем шаблоне:
<div class="card">
<div class="card-header">
<h4>{{pageTitle}}</h4>
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
</mat-form-field>
</div>
<div class="card-body p-0">
<div class="mat-elevation-z8">
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="projectNumber">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Werf Nummer </th>
<td mat-cell *matCellDef="let row"> W{{row.projectNumber}} </td>
</ng-container>
<ng-container matColumnDef="description">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Omschrijving </th>
<td mat-cell *matCellDef="let row"> {{row.description}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;">
</tr>
</table>
<mat-paginator [pageSizeOptions]="[10,20,100]"></mat-paginator>
</div>
</div>
</div>
В моем классе угловых компонентов у меня есть
export class ProjectListComponent {
pageTitle = 'Projects';
displayedColumns: string[] = ['projectNumber', 'description'];
dataSource: MatTableDataSource<Project>;
@ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;
@ViewChild(MatSort, {static: true}) sort: MatSort;
@Input() set projects(value: Project[]){
this.dataSource = new MatTableDataSource(value);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
@Input() selectedProject: Project;
@Output() selected = new EventEmitter<Project>();
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
if (this.dataSource.paginator) {
this.dataSource.paginator.firstPage();
}
}
}
Я должен упомянуть еще кое-что, что действительно интересно о параметрах фильтрации. Обратите внимание, что проект здесь используется только для двух полей, но интерфейс на самом деле состоит из большего количества полей, например, у него есть идентификатор. Несмотря на то, что я не показываю идентификатор, я могу фильтровать по идентификатору с помощью приведенного выше кода, что довольно круто.
export interface Project {
id: string;
projectNumber: string;
description: string;
activePeriods: ProjectActivePeriod[];
}
Также обратите внимание, что ссылка matColumnDef="projectNumber" в отображаемом вами столбце обязательно должна быть точным именем свойства в интерфейсе. Если бы я использовал " P rojectNumber", вид не будет работать.
Я строю это на основе информации
<table mat-table matSort #empTbSort="matSort" [dataSource]="dataSource">
@ViewChild('empTbSort') sort = new MatSort();
ngOnInit(): void {
// async call
this.dataSource = new MatTableDataSource<any>(data);
// make sure to put you sore after init dataSource
this.dataSource.sort = this.sort;
}
Как работает сортировка по мат-таблице? MatTableDataSource сортирует данные, сопоставляя имя столбца (matColumnDef) с именем свойства записи таблицы.
displayedColumns: string[] = ['ID', 'firstname', 'lastname','EmAil'];
export interface Employee
{
ID: number,
firstname:string,
lastname:string,
EmAil:string,
}
Имя свойства должно совпадать с matColumnDef, иначе столбец таблицы не будет сортироваться.
подробнее: https://www.angularjswiki.com/material/mat-table-sort/
В дополнение ко всем другим ответам, если у вас есть несколько таблиц с сортировкой в вашем шаблоне, вам необходимо определить уникальные
matSort
как показано ниже:
Шаблон:
<mat-table [dataSource]="firstDataSource" matSort #firstSort="matSort">
Составная часть:
@ViewChild('firstSort', { static: false }) firstSort: MatSort;
ngAfterViewInit() {
this.firstDataSource.sort = this.firstSort;
}
У меня была такая же проблема,
У этой проблемы есть несколько причин.
- Убедитесь, что вы включили модуль MatSortModule в свой модуль приложения.
import { MatSortModule, MatPaginatorModule, MatTableModule } from '@angular/material';
@NgModule({
imports: [MatSortModule, MatPaginatorModule, MatTableModule],
exports: []
})
- Убедитесь, что вы подписались на изменение сортировки в ngAfterViewInit
ngAfterViewInit() {
this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0 );
}
Я обновляю свои данные из внешнего источника, и по какой-то причине, когда я изменил свою переменную, таблица не обновлялась. Затем я наблюдал за изменениями вngOnChanges
и обновилdata
затем переменная отображала мою таблицу, но не позволяла сортировать. Вот что, наконец, сработало для меня:
dataSource: MatTableDataSource<BasicTableData>;
constructor() { }
ngOnInit(): void {
this.dataSource = new MatTableDataSource(this.data);
}
ngAfterViewInit() {
this.dataSource.sort = this.sort;
}
ngOnChanges(changes: SimpleChanges): void {
if(changes['data'].currentValue !== changes['data'].previousValue && !changes['data'].firstChange){
this.dataSource.data = changes['data'].currentValue;
}
}
Для меня, хотя я заявил
dataSource: MatTableDataSource<MyRowEntity>
Я все еще устанавливал его в массив (что потребовало бы явного вызова matTableChild.renderRows())
// renderRows not called automatically onSortChange
dataSource = [{name: 'hello'}, {name: 'world'}]
Решение:
// renderRows called automatically onSortChange
this.dataSource = new MatTableDataSource(myRowEntities);
PS В исходном вопросе нет этой ошибки, но я подумал, что другие могут
Для меня я забыл поставить
matSort
подпирать
<table/>
.
<table mat-table matSort [dataSource]="dataSource">
Если данные находятся внутри объекта, сортировка также не будет работать. Например:
interface: Name { firstName: string; lastName: string; }
interface: User { name: Name; }
{{ user.Name.firstName }}
Сортировка в этом случае не работает. Он должен быть плоским, как:
{{ user.firstName }}
Кроме того, имя свойства и имена столбцов должны совпадать.