私は mat-table を使って、ユーザーが選んだ言語の内容をリストしています。ダイアログパネルを使って新しい言語を追加することもできます。彼らが言語を追加して戻った後。データソースを更新して、それらが行った変更を表示します。
サービスからユーザーデータを取得し、それをrefreshメソッドでデータソースに渡すことで、データストアを初期化します。
Language.component.ts
import { Component, OnInit } from '@angular/core';
import { LanguageModel, LANGUAGE_DATA } from '../../../../models/language.model';
import { LanguageAddComponent } from './language-add/language-add.component';
import { AuthService } from '../../../../services/auth.service';
import { LanguageDataSource } from './language-data-source';
import { LevelbarComponent } from '../../../../directives/levelbar/levelbar.component';
import { DataSource } from '@angular/cdk/collections';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { MatSnackBar, MatDialog } from '@angular/material';
@Component({
selector: 'app-language',
templateUrl: './language.component.html',
styleUrls: ['./language.component.scss']
})
export class LanguageComponent implements OnInit {
displayedColumns = ['name', 'native', 'code', 'level'];
teachDS: any;
user: any;
constructor(private authService: AuthService, private dialog: MatDialog) { }
ngOnInit() {
this.refresh();
}
add() {
this.dialog.open(LanguageAddComponent, {
data: { user: this.user },
}).afterClosed().subscribe(result => {
this.refresh();
});
}
refresh() {
this.authService.getAuthenticatedUser().subscribe((res) => {
this.user = res;
this.teachDS = new LanguageDataSource(this.user.profile.languages.teach);
});
}
}
language-data-source.ts
import {MatPaginator, MatSort} from '@angular/material';
import {DataSource} from '@angular/cdk/collections';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/map';
export class LanguageDataSource extends DataSource<any> {
constructor(private languages) {
super();
}
connect(): Observable<any> {
return Observable.of(this.languages);
}
disconnect() {
// No-op
}
}
そのため、バックエンドからユーザーを取得してからデータソースを再初期化するrefreshメソッドを呼び出すことを試みました。しかしこれはうまくいきません、変化は起きていません。
新しいデータを受信した直後にrefresh()
メソッドで ChangeDetectorRef
を使用して変更検出をトリガーし、コンストラクタで ChangeDetectorRef を注入して detectChanges を使用するには、次のようにします。
import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import { LanguageModel, LANGUAGE_DATA } from '../../../../models/language.model';
import { LanguageAddComponent } from './language-add/language-add.component';
import { AuthService } from '../../../../services/auth.service';
import { LanguageDataSource } from './language-data-source';
import { LevelbarComponent } from '../../../../directives/levelbar/levelbar.component';
import { DataSource } from '@angular/cdk/collections';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import { MatSnackBar, MatDialog } from '@angular/material';
@Component({
selector: 'app-language',
templateUrl: './language.component.html',
styleUrls: ['./language.component.scss']
})
export class LanguageComponent implements OnInit {
displayedColumns = ['name', 'native', 'code', 'level'];
teachDS: any;
user: any;
constructor(private authService: AuthService, private dialog: MatDialog,
private changeDetectorRefs: ChangeDetectorRef) { }
ngOnInit() {
this.refresh();
}
add() {
this.dialog.open(LanguageAddComponent, {
data: { user: this.user },
}).afterClosed().subscribe(result => {
this.refresh();
});
}
refresh() {
this.authService.getAuthenticatedUser().subscribe((res) => {
this.user = res;
this.teachDS = new LanguageDataSource(this.user.profile.languages.teach);
this.changeDetectorRefs.detectChanges();
});
}
}
質問が作成されたときにChangeDetectorRef
が必要だったかどうかはわかりませんが、これで十分です。
import { MatTableDataSource } from '@angular/material/table';
// ...
dataSource = new MatTableDataSource<MyDataType>();
refresh() {
this.myService.doSomething().subscribe(data: MyDataType[] => {
this.dataSource.data = data;
}
}
だから私にとっては、私が遭遇した問題に対して良い答えを出した人は誰もいません。それは@Kayとほとんど同じです。私にとってはソートについてです、ソートテーブルはマットの中では変化しません。それは私がグーグルを検索することによって見つける唯一のトピックであるので私はこの答えを目的としています。私はAngular 6を使っています。
言ったように ここ :
テーブルはパフォーマンスを最適化するため、データ配列への変更を自動的にチェックしません。代わりに、オブジェクトがデータ配列上で追加、削除、または移動されたときに、そのrenderRows()メソッドを呼び出すことによって、テーブルのレンダリングされた行の更新をトリガできます。
変更を反映させるには、 refresh() メソッドで renderRows() を呼び出すだけです。
統合については ここ を参照してください。
MatPaginator
を使用しているので、ページ番号を変更するだけで、データの再ロードが引き起こされます。
簡単なトリック:
this.paginator._changePageSize(this.paginator.pageSize);
これはページサイズを現在のページサイズに更新するので、基本的には何も変更されません。プライベートの_emitPageEvent()
関数も呼ばれ、テーブルのリロードがトリガされます。
this.dataSource = new MatTableDataSource<Element>(this.elements);
特定の行を追加または削除するアクションの下にこの行を追加します。
refresh() {
this.authService.getAuthenticatedUser().subscribe((res) => {
this.user = new MatTableDataSource<Element>(res);
});
}
これを行うための最善の方法は、追加のオブザーバブルをデータソース実装に追加することです。
Connectメソッドでは、paginator.pageやsort.sortChangeなどを含むオブザーバブルの配列をサブスクライブするためにObservable.merge
をすでに使用しているはずです。これに新しい件名を追加して、リフレッシュを必要とするときに次に呼び出すことができます。 。
このようなもの:
export class LanguageDataSource extends DataSource<any> {
recordChange$ = new Subject();
constructor(private languages) {
super();
}
connect(): Observable<any> {
const changes = [
this.recordChange$
];
return Observable.merge(...changes)
.switchMap(() => return Observable.of(this.languages));
}
disconnect() {
// No-op
}
}
そしてrecordChange$.next()
を呼び出してリフレッシュを開始することができます。
当然、この呼び出しをrefresh()メソッドでラップし、コンポーネント内のデータソースインスタンス、およびその他の適切な方法で呼び出します。
あなただけのデータソース接続機能を使用することができます
this.datasource.connect().next(data);
そのようです。 'data'はデータテーブルの新しい値です
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
export class LanguageComponent implemnts OnInit {
displayedColumns = ['name', 'native', 'code', 'leavel'];
user: any;
private update = new Subject<void>();
update$ = this.update.asObservable();
constructor(private authService: AuthService, private dialog: MatDialog) {}
ngOnInit() {
this.update$.subscribe(() => { this.refresh()});
}
setUpdate() {
this.update.next();
}
add() {
this.dialog.open(LanguageAddComponent, {
data: { user: this.user },
}).afterClosed().subscribe(result => {
this.setUpdate();
});
}
refresh() {
this.authService.getAuthenticatedUser().subscribe((res) => {
this.user = res;
this.teachDS = new LanguageDataSource(this.user.profile.languages.teach);
});
}
}
私の場合(Angular 6+)、私はMatTableDataSource
から継承してMyDataSource
を作成しました。 呼び出しなし this.data = someArray
の後
this.entitiesSubject.next(this.data as T[])
表示されていないデータ
export class MyDataSource<T extends WhateverYouWant> extends MatTableDataSource<T> {
private entitiesSubject = new BehaviorSubject<T[]>([]);
loadDataSourceData(someArray: T[]){
this.data = someArray //whenever it comes from an API asyncronously or not
this.entitiesSubject.next(this.data as T[])// Otherwise data not displayed
}
public connect(): BehaviorSubject<T[]> {
return this.entitiesSubject
}
}//end Class
"concat"を使ってテーブルのデータを簡単に更新することができます。
例えば:
language.component.ts
teachDS: any[] = [];
language.component.html
<table mat-table [dataSource]="teachDS" class="list">
そして、あなたがデータ(language.component.ts)を更新するとき:
addItem() {
// newItem is the object added to the list using a form or other way
this.teachDS = this.teachDS.concat([newItem]);
}
「concat」角度を使用している場合は、オブジェクトの変更を検出し(this.teachDS)、他に使用する必要はありません。
PD:それは角度6と角度7で私のために働きます、私は別のバージョンを試しませんでした。
MatTableDataSource
オブジェクトは、MatTableDataSource
コンストラクタに渡すデータ配列と何らかの形でリンクされていると思います。
例えば:
dataTable: string[];
tableDS: MatTableDataSource<string>;
ngOnInit(){
// here your pass dataTable to the dataSource
this.tableDS = new MatTableDataSource(this.dataTable);
}
だから、あなたがデータを変更しなければならないとき。元のリストのdataTable
を変更してから、tableDS
の_updateChangeSubscription()
メソッドを呼び出してテーブルの変更を反映します。
例えば:
this.dataTable.Push('testing');
this.tableDS._updateChangeSubscription();
それはAngular 6を通して私と一緒に働いています。
読んだ後 材料表が更新後のデータ更新を更新していません#11638バグレポート 私は、最良の(読む、最も簡単な解決策)がEventEmitterを使うことを提案した最後の解説者 'shhdharmen'によって示唆されたものであることを見つけました。
これには、生成されたデータソースクラスに対するいくつかの簡単な変更が含まれます。
すなわち)あなたのデータソースクラスに新しいプライベート変数を追加する
import { EventEmitter } from '@angular/core';
...
private tableDataUpdated = new EventEmitter<any>();
そして私が新しいデータを内部配列(this.data)にプッシュするところで、私はイベントを発行します。
public addRow(row:myRowInterface) {
this.data.Push(row);
this.tableDataUpdated.emit();
}
そして最後に、 'connect'メソッドの 'dataMutation'配列を以下のように変更します。
const dataMutations = [
this.tableDataUpdated,
this.paginator.page,
this.sort.sortChange
];
//これはdataSourceです
this.guests = [];
this.guests.Push({id:1、name: 'Ricardo'});
// dataSourceを更新しますthis.guests = Array.from(this.guest);
私はもう少し調査をして、私が必要としているものを私に与えるためにこの場所を見つけました - サーバーからリフレッシュされたとききれいに感じそして更新データに関連します: https://blog.angular-university.io/angular-material-data-table/
上のページへのほとんどのクレジット。以下は、選択の変更時にデータソースにバインドされたマットテーブルを更新するためにマットセレクターを使用する方法の例です。私はAngular 7を使用しています。完全ではあるが簡潔にするために、広範囲に渡って申し訳ありません。他の誰かがより早く進むのを手助けすることを願っています!
organization.model.ts:
export class Organization {
id: number;
name: String;
}
organization.service.ts:
import { Observable, empty } from 'rxjs';
import { of } from 'rxjs';
import { Organization } from './organization.model';
export class OrganizationService {
getConstantOrganizations(filter: String): Observable<Organization[]> {
if (filter === "All") {
let Organizations: Organization[] = [
{ id: 1234, name: 'Some data' }
];
return of(Organizations);
} else {
let Organizations: Organization[] = [
{ id: 5678, name: 'Some other data' }
];
return of(Organizations);
}
// ...just a sample, other filterings would go here - and of course data instead fetched from server.
}
organizationdatasource.model.ts:
import { CollectionViewer, DataSource } from '@angular/cdk/collections';
import { Observable, BehaviorSubject, of } from 'rxjs';
import { catchError, finalize } from "rxjs/operators";
import { OrganizationService } from './organization.service';
import { Organization } from './organization.model';
export class OrganizationDataSource extends DataSource<Organization> {
private organizationsSubject = new BehaviorSubject<Organization[]>([]);
private loadingSubject = new BehaviorSubject<boolean>(false);
public loading$ = this.loadingSubject.asObservable();
constructor(private organizationService: OrganizationService, ) {
super();
}
loadOrganizations(filter: String) {
this.loadingSubject.next(true);
return this.organizationService.getOrganizations(filter).pipe(
catchError(() => of([])),
finalize(() => this.loadingSubject.next(false))
).subscribe(organization => this.organizationsSubject.next(organization));
}
connect(collectionViewer: CollectionViewer): Observable<Organization[]> {
return this.organizationsSubject.asObservable();
}
disconnect(collectionViewer: CollectionViewer): void {
this.organizationsSubject.complete();
this.loadingSubject.complete();
}
}
organization.component.html:
<div class="spinner-container" *ngIf="organizationDataSource.loading$ | async">
<mat-spinner></mat-spinner>
</div>
<div>
<form [formGroup]="formGroup">
<mat-form-field fxAuto>
<div fxLayout="row">
<mat-select formControlName="organizationSelectionControl" (selectionChange)="updateOrganizationSelection()">
<mat-option *ngFor="let organizationSelectionAlternative of organizationSelectionAlternatives"
[value]="organizationSelectionAlternative">
{{organizationSelectionAlternative.name}}
</mat-option>
</mat-select>
</div>
</mat-form-field>
</form>
</div>
<mat-table fxLayout="column" [dataSource]="organizationDataSource">
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef>Name</mat-header-cell>
<mat-cell *matCellDef="let organization">{{organization.name}}</mat-cell>
</ng-container>
<ng-container matColumnDef="number">
<mat-header-cell *matHeaderCellDef>Number</mat-header-cell>
<mat-cell *matCellDef="let organization">{{organization.number}}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>
organization.component.scss:
.spinner-container {
height: 360px;
width: 390px;
position: fixed;
}
organization.component.ts:
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder } from '@angular/forms';
import { Observable } from 'rxjs';
import { OrganizationService } from './organization.service';
import { Organization } from './organization.model';
import { OrganizationDataSource } from './organizationdatasource.model';
@Component({
selector: 'organizations',
templateUrl: './organizations.component.html',
styleUrls: ['./organizations.component.scss']
})
export class OrganizationsComponent implements OnInit {
public displayedColumns: string[];
public organizationDataSource: OrganizationDataSource;
public formGroup: FormGroup;
public organizationSelectionAlternatives = [{
id: 1,
name: 'All'
}, {
id: 2,
name: 'With organization update requests'
}, {
id: 3,
name: 'With contact update requests'
}, {
id: 4,
name: 'With order requests'
}]
constructor(
private formBuilder: FormBuilder,
private organizationService: OrganizationService) { }
ngOnInit() {
this.formGroup = this.formBuilder.group({
'organizationSelectionControl': []
})
const toSelect = this.organizationSelectionAlternatives.find(c => c.id == 1);
this.formGroup.get('organizationSelectionControl').setValue(toSelect);
this.organizationDataSource = new OrganizationDataSource(this.organizationService);
this.displayedColumns = ['name', 'number' ];
this.updateOrganizationSelection();
}
updateOrganizationSelection() {
this.organizationDataSource.loadOrganizations(this.formGroup.get('organizationSelectionControl').value.name);
}
}
これは私のために働いています:
dataSource = new MatTableDataSource<Dict>([]);
public search() {
let url = `${Constants.API.COMMON}/dicts?page=${this.page.number}&` +
(this.name == '' ? '' : `name_like=${this.name}`);
this._http.get<Dict>(url).subscribe((data)=> {
// this.dataSource = data['_embedded'].dicts;
this.dataSource.data = data['_embedded'].dicts;
this.page = data['page'];
this.resetSelection();
});
}
そのため、データソースインスタンスをMatTableDataSource
として宣言する必要があります。
これは私のために働いた:
refreshTableSorce() {
this.dataSource = new MatTableDataSource<Element>(this.newSource);
}
2つのリソースを使用して、優れたソリューションを実現しました。
データソースとページネーターの両方を更新:
this.datasource.connect().next(data);
this.paginator._changePageSize(this.paginator.pageSize);