2つのコンポーネントがあります。どちらにもマットテーブルとページネーターがあり、ページネーションは1つのコンポーネントで機能し、他のコンポーネントでは機能しませんが、コードは似ています。以下は私のhtmlです。
<div class="mat-elevation-z8">
<mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="col1">
<mat-header-cell *matHeaderCellDef mat-sort-header> Column1 </mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.col1}} </mat-cell>
</ng-container>
<ng-container matColumnDef="col2">
<mat-header-cell *matHeaderCellDef mat-sort-header> Column2 </mat-header-cell>
<mat-cell *matCellDef="let row"> {{row.col2}} </mat-cell>
</ng-container>
<!-- Different columns goes here -->
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;">
</mat-row>
</mat-table>
<mat-paginator #scheduledOrdersPaginator [pageSizeOptions]="[5, 10, 20]"></mat-paginator>
</div>
そして、以下はcomponent.tsの私のコードです:
dataSource: MatTableDataSource<any>;
displayedColumns = ['col1', 'col2', ... ];
@ViewChild('scheduledOrdersPaginator') paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
ngOnInit(): void {
// Load data
this.dataSource = new MatTableDataSource(somearray);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
他のコンポーネントでも同様のコードが機能し、ページネーションでテーブルが適切にレンダリングされます。このコードの何が問題なのかはわかりません。
どんな助けも本当に感謝されます
インスタンス化をタイムアウトで囲むことにより、同様の問題を解決しました。これを試して :
setTimeout(() => this.dataSource.paginator = this.paginator);
私の場合、<mat-paginator>
要素は*ngIf
を持つコンテナ内にあり、データが非同期にロードされるまでレンダリングしませんでした。これにより、this.paginator
はundefined
であってもngAfterViewInit
になります。 MatTableDataSource
をpaginator
に設定しても、undefined
に問題はないため、これはサイレントに失敗します。
解決策は、<mat-paginator>
を*ngIf
'dコンテナの外に移動することでした
うまくいけば、これは私と同じ状況にいる人を助けます。
選択された答えは機能し、問題を解決しますが、依然として回避策です。これは、問題に対処するための適切でエレガントな方法です。
AfterViewInit
インターフェイスをクラスに追加してから、this.dataSource.paginator = this.paginator
をngAfterViewInit()
メソッド内に配置してください
ngAfterViewInit() {
this.dataSource.paginator = this.paginator
}
回避策setTimeout
を呼び出す必要はありません。
データソースを設定した直後にChangeDetectorRef.detectChanges()を呼び出します。
// First import ChangeDetectorRef & Material related stuff
import { ..., ChangeDetectorRef } from '@angular/core';
import { MatSort, MatTableDataSource, MatPaginator } from '@angular/material';
// Set properties in your component
@ViewChild(MatSort) sort: MatSort;
@ViewChild(MatPaginator) paginator: MatPaginator;
// Inject in constructor
constructor (..., private cdr: ChangeDetectorRef, ...) { ... }
// Set data source and invoke detectChanges()
this.dataSource = new MatTableDataSource (MY_DATA);
this.cdr.detectChanges();
// after that you can set other properties like
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;
それを機能させるには、データがソースからフェッチされた後にページネータを設定する必要がありました
getVariables() {
this.activeRoute.params.subscribe(params => {
if (params['id'] && (params['type'] === Type.CodeList)) {
this.dataService
.getItems(this.currentLanguage, params['id'])
.subscribe((items: any) => {
this.dataSource.data = this.items;
this.dataSource.paginator = this.paginator;
})
}
})
}
私はangularとTypeScriptの初心者ですが、同じ問題を抱えた後(ただし、並べ替えが機能しなかったということを除いて)、関数 'refreshDataScource()
'とサーバーが新しいデータで応答するたびに、ngAfterViewInit()
から呼び出されます。この関数では、ページネータとソートでdataSource
を更新するだけです。このような:
refreshDataSource() {
this.dataSource = new MatTableDataSource(myDataArray);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
ページ付けと並べ替えを修正しました。すべてが完全に機能するようになりました。ただし、それが単なる回避策なのか実際の修正なのかはわかりません。
変更のみ
dataSource: MatTableDataSource<any>;
for
dataSource = new MatTableDataSource();
dataSource = new MatTableDataSource();
displayedColumns = ['col1', 'col2', ... ];
@ViewChild('scheduledOrdersPaginator') paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
ngOnInit(): void {
// Load data
this.dataSource = new MatTableDataSource(somearray);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
setTimeOut()を使用すると、問題が一時的に解決されますが、MatDataSourceに大量のデータ(たとえば1000行)をプッシュしている場合、これは再び機能しません。
データソースページネータを設定する前に大きなデータセットを設定すると、MatTableのロードが非常に遅くなることがわかりました。
ngOninit(){
// initialize dataSource here
}
ngAfterViewInit() {
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;
/* now it's okay to set large data source... */
this.dataSource.data = [GetLargeDataSet];}
そのため、最初にデータソースを初期化し、「Paginator」や「Sort」などのプロパティを設定してから、データをソースに「Data」プロパティにプッシュします。
私は同じ問題を抱えていました(テーブルデータは表示されますが、MatPaginatorは機能しません)。私の場合、「新しいMatTableDataSource」を作成するのを忘れました
this.dataSource = somearray;
this.dataSource = new MatTableDataSource(somearray);
が有効になっている間は、MatPaginatorを有効にしないでください。
素材ドキュメント から抽出
「データの配列をソート、ページ分割、フィルタリングできるテーブルを使用するユースケースを簡素化するために、Angular MaterialライブラリにはMatTableDataSourceは、現在のテーブル状態に従ってどの行をレンダリングするかを決定するロジックを既に実装しています。」
この答えが誰かを助けることを願っています。
私が見つけた解決策は、データが正常にロードされた後にページネーターを設定することです。
this._empService.GetEmpList().subscribe(
data => {
this.empListDataSource = new MatTableDataSource<empToShow>(Object.values(data))
this.empListDataSource.paginator = this.paginator
}
)
app.module.ts
にMatPaginatorModule
をインポートしたことを確認してください
これにより、テーブルが機能しなかった理由を最終的に追跡して理解するのにhoursかかりました。 console.logs()をいくつか配置することで、イベントの順序と、一貫して機能しない理由を把握することができました。私のシナリオは、動的データソースに関する上記の元の問題と似ていましたが、わずかに異なっていました。私にとっては、最初にangularアプリを更新すると、ページネーターの状態が設定され、次にテーブルのデータが設定されます。これらのイベントがこの順序で発生すると、ページネーターは予想どおりに機能しました。
ReplaySubjectsを使用してテーブルのデータを取得しているため、paginatorの状態がngAfterViewInitに設定され、テーブルデータがサブスクリプションから取得されます(ユーザーIDに依存するため、初期値があり、それがBehaviorSubjectsを使用しなかった理由です。私の問題は、アプリ内の別のコンポーネントに移動して動的テーブルデータソースに戻ると、ページデータがページネーターの状態の前に設定されることでした。これにより、ページネーターはページxを表示しますが、表示されるデータは常にデータの最初のページになります。
この迷惑な問題を修正するには:
setTableData() {
// set table data
this.tableData.data = this.images.filter(img => this.filterData(img));
// some other code below
....
}
// initialize our data source for our table and set flags for state
tableData = new MatTableDataSource<IImage>(this.images);
loading = true;
setPageState = false;
ngAfterViewInit() {
// add pagination state to our table
setTimeout(() => {
console.log('Set paginator state');
this.setPageState = true;
this.paginator.pageIndex = this.state.pageIndex;
// check if we are not loading data, meaning the table came in first so
// we need to set the data here
if (!this.loading) {
this.setTableData();
}
}, 0);
}
ngOnInit() {
console.log('ngOnInit');
this.tableData.sort = this.sort;
this.tableData.paginator = this.paginator;
// listen for data
this.dbService.images.subscribe(images => {
console.log('Data subscription');
// save images
this.images = images;
// only set table data if paginator state has been set, otherwise it doesnt work
if (this.setPageState) {
this.setTableData();
}
// hide spinner and update that we have data
this.loading = false;
});
// other code
.....
}
それで、アプリに初めてログインしたときと、他のページに移動して動的テーブルに戻るときのページネーションが、ようやく一貫して機能しました。
上記のすべてのソリューションを試した後、ようやくシンプルなソリューションが機能しました。誰かが立ち往生した場合、私は参考のために投稿しています。
Angular 8.を使用しています。子参照に{static:false}を追加するだけです
@ViewChild(MatSort, { static: false }) sort: MatSort;
@ViewChild(MatPaginator, {static: false}) paginator: MatPaginator;
私はこれを使用していました:
@ViewChild(MatSort、{read:true、static:false})sort:MatSort;
@ViewChild(MatPaginator、{read:true、static:false})paginator:MatPaginator;
<mat-paginator
#scheduledOrdersPaginator
(page)="pageEvent($event)">
</mat-paginator>
pageEvent(event){
//it will run everytime you change paginator
this.dataSource.paginator = this.paginator;
}
setTimeout
を使用しないソリューションは、set
を使用することです。
@ViewChild(MatPaginator) paginator: MatPaginator;
set matPaginator(mp: MatPaginator) {
this.paginator = mp;
this.dataSource.paginator = this.paginator;
}
私もこの問題を抱えていました。参照scheduledOrdersPaginatorをpagintaorタグに追加し、@ ViewChildで受信しました。ページネーションの問題を解決しました。以下のコードは他の人を助けるかもしれません。
dataSource = new MatTableDataSource();
displayedColumns = ['col1', 'col2', ... ];
@ViewChild('scheduledOrdersPaginator') paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
ngOnInit(): void {
// Load data
this.dataSource = new MatTableDataSource(somearray);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
html:
<mat-paginator #scheduledOrdersPaginator [pageSizeOptions]="[5, 10, 20]" showFirstLastButtons> </mat-paginator>
私の場合、サービスからのデータは非同期に取得されるため、どちらもngOnInitもngAfterViewInitも使用できません。ngOnChangesは次のように使用します。
ngOnChanges(change: SimpleChanges) {
if (change.properties) {
if (this.properties.length > 0) {
this.dataSource = new MatTableDataSource(this.properties);
this.dataSource.paginator = this.paginator;
}
}
}
Htmlのmat-table要素の[DataSource]属性をコンポーネントのデータソースプロパティに設定して、データソースがテーブルおよびページネーターと確実にバインドされるようにしてください。
これを確認してください Stackoverflow Answer 。
HTMLコンポーネントが読み込まれた後(* ngIf)でTypeScriptにページネーターを設定すると、問題が修正されました。
リンクの説明をここに入力 テーブルのデータをページ分割するには、テーブルの後にaを追加します。
テーブルのデータソースにMatTableDataSourceを使用している場合は、MatPaginatorをデータソースに提供するだけです。ユーザーによって行われたページ変更を自動的にリッスンし、適切なページデータをテーブルに送信します。
それ以外の場合、データをページ分割するロジックを実装している場合は、ページネータ(ページ)の出力をリッスンし、データの適切なスライスをテーブルに渡す必要があります。
の使用と設定の詳細については、mat-paginatorのドキュメントをご覧ください。
MatPaginatorは、テーブルのデータをページ分割するために提供されるソリューションの1つですが、唯一のオプションではありません。実際、MatTableとそのインターフェイスは特定の実装に関連付けられていないため、テーブルはカスタムのページ分割UIまたは戦略で機能します。
@ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;
ngOnInit() {
this.dataSource.paginator = this.paginator;
}