wake-up-neo.com

Winkel + Material - So aktualisieren Sie eine Datenquelle (mat-table)

Ich verwende eine mat-table , um den Inhalt der von den Benutzern ausgewählten Sprachen aufzulisten. Sie können auch neue Sprachen über das Dialogfenster hinzufügen. Nachdem sie eine Sprache hinzugefügt und zurückgekehrt sind. Ich möchte, dass meine Datenquelle aktualisiert wird, um die vorgenommenen Änderungen anzuzeigen. 

Ich initialisiere den Datenspeicher, indem ich Benutzerdaten von einem Dienst abrufe und diese in der Aktualisierungsmethode an eine Datenquelle übergibt.

Sprachenkomponente.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);   
    });
  }
}

sprache-datenquelle.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
  }

}

Also habe ich versucht, eine Refresh-Methode aufzurufen, bei der ich den Benutzer wieder aus dem Backend bekomme und dann die Datenquelle erneut initialisiert. Dies funktioniert jedoch nicht, es treten keine Änderungen auf.

38
Kay

Lösen Sie eine Änderungserkennung aus, indem Sie ChangeDetectorRef in der refresh()-Methode verwenden Direkt nach Erhalt der neuen Daten injizieren Sie ChangeDetectorRef im Konstruktor und verwenden Sie detectChanges wie folgt:

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();
    });
  }
}
30
HDJEMAI

Ich weiß nicht, ob die ChangeDetectorRef zum Zeitpunkt der Erstellung der Frage erforderlich war, aber jetzt ist das genug:

import { MatTableDataSource } from '@angular/material/table';

// ...

dataSource = new MatTableDataSource<MyDataType>();

refresh() {
  this.myService.doSomething().subscribe(data: MyDataType[] => {
    this.dataSource.data = data;
  }
}
24
MA-Maddin

Für mich gab also niemand die gute Antwort auf das Problem, das ich traf, was fast dasselbe ist wie @ Kay. Für mich geht es um das Sortieren, das Sortieren der Tabelle findet nicht in der Matte statt. Ich benutze diese Antwort, da es das einzige Thema ist, das ich bei der Suche von Google finde.

Wie gesagt hier :

Da die Tabelle für die Leistung optimiert wird, wird sie nicht automatisch auf Änderungen am Datenarray überprüft. Wenn Objekte im Datenarray hinzugefügt, entfernt oder verschoben werden, können Sie stattdessen eine Aktualisierung der gerenderten Zeilen der Tabelle auslösen, indem Sie ihre renderRows () - Methode aufrufen.

Sie müssen also nur renderRows () in Ihrer refresh () - Methode aufrufen, damit Ihre Änderungen angezeigt werden.

hier für die Integration.

10
4x10m

Da Sie MatPaginator verwenden, müssen Sie lediglich eine Änderung am Paginator vornehmen. Dadurch wird das Neuladen der Daten ausgelöst.

Einfacher Trick:

this.paginator._changePageSize(this.paginator.pageSize); 

Dadurch wird die Seitengröße auf die aktuelle Seitengröße aktualisiert. Daher ändert sich im Wesentlichen nichts, außer die private Funktion _emitPageEvent() wird aufgerufen, die das erneute Laden der Tabelle auslöst.

10
takeshin

Dies erreichen Sie am besten, indem Sie Ihrer Datenquellenimplementierung ein zusätzliches Observable hinzufügen.

In der connect-Methode sollten Sie Observable.merge bereits verwenden, um ein Array von Observables zu abonnieren, zu dem paginator.page, sort.sortChange usw. gehören. Sie können einen neuen Betreff hinzufügen und den nächsten Betreff aufrufen, wenn Sie eine Aktualisierung durchführen müssen .

etwas wie das:

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
    }
}

Und dann können Sie recordChange$.next() aufrufen, um eine Aktualisierung zu starten.

Natürlich würde ich den Aufruf in eine refresh () - Methode einschließen und ihn von der Datenquelleninstanz w/in der Komponente sowie von anderen geeigneten Techniken abrufen.

6
jogi

this.dataSource = new MatTableDataSource (this.elements);

Fügen Sie diese Zeile unterhalb Ihrer Aktion zum Hinzufügen oder Löschen der jeweiligen Zeile hinzu.

refresh() {
  this.authService.getAuthenticatedUser().subscribe((res) => {
    this.user = new MatTableDataSource<Element>(res);   
  });
}
5
Pooja Paigude

Sie können einfach die Datenquellen-Verbindungsfunktion verwenden

this.datasource.connect().next(data);

wie so. 'data' sind die neuen Werte für die Datentabelle

2
cozmik05
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);   
    });
  }
}
2

in meinem Fall (Winkel 6+) habe ich von MatTableDataSource geerbt, um MyDataSource zu erstellen. Ohne Aufruf nach this.data = someArray

this.entitiesSubject.next(this.data as T[])

daten wo nicht angezeigt

klasse MyDataSource

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 
1
Pipo

Sie können die Daten der Tabelle einfach mit "concat" aktualisieren:

zum Beispiel:

language.component.ts

teachDS: any[] = [];

language.component.html

<table mat-table [dataSource]="teachDS" class="list">

Und wenn Sie die Daten aktualisieren (language.component.ts):

addItem() {
    // newItem is the object added to the list using a form or other way
    this.teachDS = this.teachDS.concat([newItem]);
 }

Wenn Sie "concat" Angular verwenden, erkennen Sie die Änderungen des Objekts (this.teachDS) und Sie müssen keine andere Sache verwenden.

PD: Es ist Arbeit für mich in Winkel 6 und 7, ich habe keine andere Version ausprobiert.

Ich denke, das MatTableDataSource-Objekt ist irgendwie mit dem Datenarray verknüpft, das Sie an den MatTableDataSource-Konstruktor übergeben.

Zum Beispiel:

dataTable: string[];
tableDS: MatTableDataSource<string>;

ngOnInit(){
   // here your pass dataTable to the dataSource
   this.tableDS = new MatTableDataSource(this.dataTable); 
}

Wenn Sie also Daten ändern müssen; Ändern Sie in der ursprünglichen Liste dataTable und spiegeln Sie dann die Änderung in der Tabelle wider, indem Sie die _updateChangeSubscription()-Methode für tableDS aufrufen.

Zum Beispiel:

this.dataTable.Push('testing');
this.tableDS._updateChangeSubscription();

Das ist die Arbeit mit mir durch Angular 6.

0
nimeresam

Nach dem Lesen von Materialtabelle nicht aktualisiert # 11638 Bug Report fand ich die beste (gelesen, die einfachste Lösung), wie vom Endkommentator 'shhdharmen' mit einem Vorschlag zur Verwendung eines EventEmitter vorgeschlagen.

Dies erfordert einige einfache Änderungen an der generierten Datenquellenklasse

dh) Fügen Sie Ihrer Datenquellenklasse eine neue private Variable hinzu

import { EventEmitter } from '@angular/core';
...
private tableDataUpdated = new EventEmitter<any>();

und wo ich neue Daten in das interne Array (this.data) schiebe, gebe ich ein Ereignis aus.

public addRow(row:myRowInterface) {
    this.data.Push(row);
    this.tableDataUpdated.emit();
}

zum Schluss ändern Sie das Array 'dataMutation' in der Methode 'connect' wie folgt

const dataMutations = [
    this.tableDataUpdated,
    this.paginator.page,
    this.sort.sortChange
];
0
Gav_at_ASTS

// das ist die dataSource
this.guests = [];

this.guests.Push ({id: 1, name: 'Ricardo'});

// Aktualisiere die Datenquelle this.guests = Array.from (this.guest);

0
Igor Faoro

Ich recherchierte weiter und fand diesen Ort, um mir das zu geben, was ich brauchte - fühlt sich sauber an und bezieht sich auf Aktualisierungsdaten, wenn sie vom Server aktualisiert werden: https://blog.angular-university.io/angular-material-data-table/

Die meisten Credits auf der Seite oben. Unten sehen Sie ein Beispiel dafür, wie ein Mat-Selector verwendet werden kann, um eine Mat-Tabelle zu aktualisieren, die bei einer Änderung der Auswahl an eine Datenquelle gebunden ist. Ich verwende Angular 7. Es tut mir leid, dass ich so umfangreich und vollständig wie möglich bin. Ich habe so viele nicht benötigte Teile wie möglich herausgerissen. In der Hoffnung, jemand anderem dabei zu helfen, schneller voranzukommen!

organisationsmodell.ts:

export class Organization {
    id: number;
    name: String;
}

organisation.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.
}

organisationsdatenquelle.modell.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();
  }
}

organisations.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>

organisations.component.scss:

.spinner-container {
    height: 360px;
    width: 390px;
    position: fixed;
}

organisationskomponente.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);
  }
}
0
Henrik

Das funktioniert für mich:

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();
  });
}

Sie sollten Ihre Datenquelleninstanz daher als MatTableDataSource deklarieren.

0
Tiny King

Das hat für mich funktioniert:

refreshTableSorce() {
    this.dataSource = new MatTableDataSource<Element>(this.newSource);
}
0

Ich habe mit zwei Ressourcen eine gute Lösung gefunden:

aktualisieren von DataSource und Paginator:

this.dataSource.data = this.users;
this.dataSource.connect().next(this.users);
this.paginator._changePageSize(this.paginator.pageSize);

wobei zum Beispiel dataSource hier definiert ist:

    users: User[];
    ...
    dataSource = new MatTableDataSource(this.users);
    ...
    this.dataSource.paginator = this.paginator;
    ...
0
danilo

nun, ich bin auf ein ähnliches Problem gestoßen, bei dem ich der Datenquelle etwas hinzufüge und es nicht auf die einfachste Art und Weise nachlädt, die ich gefunden habe, nur um die Daten neu zu sortieren

let dataSource = ['a','b','c']
dataSource.Push('d')
let cloned = dataSource.slice()
// OR IN ES6 // let cloned = [...dataSource]
dataSource = cloned
0
Mordy Stern
npm install @matheo/datasource

Ich habe eine Bibliothek veröffentlicht, die die offizielle Material DataSource für die Zukunft sein soll. Sie unterstützt alle Arten von Eingabestreams (Sortieren, Paginieren, Filtern) und einige Konfigurationen mit Debugging, um zu sehen, wie es beim Codieren funktioniert.

import { MatDataSourceModule } from '@matheo/datasource';

Die StackBlitz-Demo und weitere Informationen finden Sie hier:
https://medium.com/@matheo/reactive-datasource-for-angular-1d869b0155f6

Ich würde mich freuen, Ihre Meinung zu hören und bei Bedarf Ihre Anwendungsfälle zu unterstützen.
Fröhliches Codieren!

0
Mateo Tibaquira