Angular + Material - วิธีรีเฟรชแหล่งข้อมูล (mat-table)


125

ฉันใช้mat-tableเพื่อแสดงเนื้อหาของภาษาที่ผู้ใช้เลือก นอกจากนี้ยังสามารถเพิ่มภาษาใหม่โดยใช้แผงโต้ตอบ หลังจากที่พวกเขาเพิ่มภาษาและกลับมา ฉันต้องการให้แหล่งข้อมูลของฉันรีเฟรชเพื่อแสดงการเปลี่ยนแปลงที่พวกเขาทำ

ฉันเริ่มต้นพื้นที่เก็บข้อมูลโดยรับข้อมูลผู้ใช้จากบริการและส่งต่อไปยังแหล่งข้อมูลในวิธีการรีเฟรช

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

ภาษาข้อมูล 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
  }

}

ดังนั้นฉันจึงพยายามเรียกวิธีการรีเฟรชที่ฉันรับผู้ใช้จากแบ็กเอนด์อีกครั้งจากนั้นฉันจึงเริ่มต้นแหล่งข้อมูลใหม่ อย่างไรก็ตามสิ่งนี้ไม่ได้ผลไม่มีการเปลี่ยนแปลงใด ๆ เกิดขึ้น


1
หากคุณต้องการทริกเกอร์การเปลี่ยนแปลง "จากแหล่งข้อมูล" โปรดดูที่stackoverflow.com/questions/47897694/…
Yennefer

ตัวปล่อยเหตุการณ์สามารถใช้ได้ในกรณีนี้ stackoverflow.com/a/44858648/8300620
Rohit Parte

คำตอบ:


59

ทริกเกอร์การตรวจจับการเปลี่ยนแปลงโดยใช้ChangeDetectorRefในrefresh()วิธีหลังจากได้รับข้อมูลใหม่ฉีด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();
    });
  }
}

9
ดูเหมือนจะได้ผลนี่เป็นวิธีที่เหมาะสมที่จะทำหรือไม่? ดูเหมือนแฮ็คนิดหน่อย ...
Kay

มีวิธีใดอีกบ้าง? คุณช่วยยกตัวอย่างในโซลูชันของคุณเพื่อหาคำตอบที่สมบูรณ์ได้ไหม
Kay


89

ฉันไม่รู้ว่าChangeDetectorRefจำเป็นหรือไม่เมื่อสร้างคำถาม แต่ตอนนี้ก็เพียงพอแล้ว:

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

// ...

dataSource = new MatTableDataSource<MyDataType>();

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

ตัวอย่าง:
StackBlitz


4
แม้ว่าโซลูชันนี้จะใช้งานได้จริง แต่จะทำให้ตัวแบ่งส่วนของวัสดุยุ่งเหยิงหากมีการเพิ่มองค์ประกอบที่อื่นนอกเหนือจากหน้าแรกของผลลัพธ์ ฉันเข้าใจว่านั่นอยู่นอกเหนือขอบเขตของคำถามนี้ แต่เนื่องจากทั้งสองมีความเกี่ยวข้องกันคุณมีวิธีแก้ปัญหาอย่างรวดเร็วที่คุณสามารถเพิ่มในคำตอบของคุณได้หรือไม่?
Knight

5
@Knight ฉันคิดว่าคุณต้องกำหนด Paginator ให้กับMatTableDataSource.paginatorคุณสมบัติหลังจากเริ่มต้นมุมมองของ Paginator แล้ว ดูคำอธิบายpaginatorคุณสมบัติที่นี่: material.angular.io/components/table/api#MatTableDataSource
Martin Schneider

ข้อมูลอ้างอิงที่ดี ฉันไม่เคยเห็นสิ่งนั้นในเอกสารมาก่อน ขอบคุณ!
Knight

2
@ MA-Maddin คุณสามารถระบุวิธีการที่เฉพาะเจาะจงมากขึ้นได้หรือไม่? ตัวอย่าง?
ณ ฐนพรรณ

@Nathanphan สาย แต่เพิ่มตัวอย่าง;)
Martin Schneider

48

ดังนั้นสำหรับฉันไม่มีใครให้คำตอบที่ดีสำหรับปัญหาที่ฉันพบซึ่งเกือบจะเหมือนกันกับ @Kay สำหรับฉันมันเกี่ยวกับการเรียงลำดับตารางการเรียงลำดับจะไม่เกิดการเปลี่ยนแปลงในเสื่อ ฉันต้องการคำตอบนี้เนื่องจากเป็นหัวข้อเดียวที่ฉันพบจากการค้นหาใน Google ฉันใช้ Angular 6

ตามที่กล่าวไว้ที่นี่ :

เนื่องจากตารางปรับให้เหมาะสมกับประสิทธิภาพจึงไม่ตรวจสอบการเปลี่ยนแปลงในอาร์เรย์ข้อมูลโดยอัตโนมัติ แต่เมื่อมีการเพิ่มลบหรือย้ายออบเจ็กต์บนอาร์เรย์ข้อมูลคุณสามารถทริกเกอร์การอัปเดตแถวที่แสดงผลของตารางได้โดยเรียกเมธอด renderRows ()

ดังนั้นคุณต้องเรียกrenderRows ()ในเมธอดrefresh ()เพื่อให้การเปลี่ยนแปลงของคุณปรากฏขึ้น

ดูการผสานรวมที่นี่


1
หากแหล่งข้อมูลตารางถูกเปลี่ยนแปลงบนไคลเอนต์คำตอบนี้คือสิ่งที่คุณอาจกำลังมองหา ใช้งานได้ดี!
Alvin Saldanha

นี่คือคำตอบที่ถูกต้องสำหรับวัสดุเชิงมุม 8
ทอม

ขอบคุณ. แต่จากออบเจ็กต์ใดที่ฉันควรเรียกว่า "renderRows ()"? อยู่ใน "this.datasource" หรือไม่
WitnessTruth

นี่ควรเป็นคำตอบที่ยอมรับได้ เยี่ยม
pl-jay

19

เนื่องจากคุณใช้MatPaginatorงานคุณเพียงแค่ต้องทำการเปลี่ยนแปลงใด ๆ กับ paginator ซึ่งจะทำให้เกิดการโหลดข้อมูลซ้ำ

เคล็ดลับง่ายๆ:

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

การดำเนินการนี้จะอัปเดตขนาดหน้าเป็นขนาดหน้าปัจจุบันโดยทั่วไปจะไม่มีการเปลี่ยนแปลงใด ๆ ยกเว้น_emitPageEvent()ฟังก์ชันส่วนตัวถูกเรียกด้วยเช่นกันทำให้เกิดการโหลดตารางซ้ำ


ฉันลองใช้รหัสของคุณแล้วไม่ได้ผล (ไม่มีผล) อย่างไรก็ตาม nextPage และ previousPage ทำงานอีกครั้ง แต่ไม่มีวิธีแก้ปัญหา
อาเหม็ดฮาสน์

_changePageSize()ไม่ถูกต้องสาธารณะ? ใช้แล้วปลอดภัยจริงหรือ? เพิ่มเติมได้ที่stackoverflow.com/questions/59093781/…
Jones

9
this.dataSource = new MatTableDataSource<Element>(this.elements);

เพิ่มบรรทัดนี้ด้านล่างการดำเนินการของคุณในการเพิ่มหรือลบแถวนั้น ๆ

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

นี่คืออะไรองค์ประกอบ
parvat

8

วิธีที่ดีที่สุดคือการเพิ่มสิ่งที่สังเกตได้เพิ่มเติมในการใช้งานแหล่งข้อมูลของคุณ

ในวิธีการเชื่อมต่อคุณควรใช้Observable.mergeเพื่อสมัครสมาชิกอาร์เรย์ของสิ่งที่สังเกตได้ซึ่งรวมถึง paginator.page, sort.sortChange และอื่น ๆ คุณสามารถเพิ่มหัวเรื่องใหม่ให้กับสิ่งนี้และเรียกสิ่งต่อไปเมื่อคุณต้องการทำให้เกิดการรีเฟรช

อะไรทำนองนี้:

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 () และเรียกมันออกจากอินสแตนซ์แหล่งข้อมูล w / ในคอมโพเนนต์และเทคนิคอื่น ๆ ที่เหมาะสม


วิธีนี้อาจเป็นวิธีที่เหมาะสม มันใช้งานได้ดีสำหรับฉัน
Manu

ฉันจะใช้สิ่งนี้ได้อย่างไรเมื่อฉันต้องการขยาย MatTableDataSource เมื่อฉันลองใช้ตัวอย่างโค้ดของคุณฉันได้รับข้อผิดพลาดProperty 'connect' in type 'customDataSource<T>' is not assignable to the same property in base type 'MatTableDataSource<T>'. Type '() => Observable<any>' is not assignable to type '() => BehaviorSubject<T[]>'. Type 'Observable<any>' is not assignable to type 'BehaviorSubject<T[]>'. Property '_value' is missing in type 'Observable<any>'.
Maurice

1
@Maurice ประเภท MatTableDataSource ใช้วิธีการเชื่อมต่อกับประเภทการส่งคืนที่แตกต่างกัน มันใช้ BehaviorSubject <t []> ซึ่งหมายความว่าคุณเพียงแค่ต้องเปลี่ยนตัวอย่างเพื่อส่งกลับสิ่งนี้แทนที่จะเป็น Observable คุณควรจะยังสามารถใช้ DataSource ได้ แต่ถ้าคุณต้องใช้ MatTableDataSource ให้ส่งคืน BehaviorSubject ที่สมัครเป็นสมาชิกของคุณที่สังเกตได้โดยสมมติว่าคุณต้องเริ่มต้นจาก หวังว่าจะช่วยได้ คุณสามารถอ้างถึงแหล่งที่มาของ MatTableDataSource สำหรับไวยากรณ์ที่แน่นอนของประเภทแหล่งข้อมูลใหม่: github.com/angular/material2/blob/master/src/lib/table/…
jogi

7

คุณสามารถใช้ฟังก์ชันการเชื่อมต่อแหล่งข้อมูล

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

เช่นนั้น. 'data' เป็นค่าใหม่สำหรับ datatable


มีศักยภาพ แต่ดูเหมือนจะไม่ได้ผล ถ้าหลังจากนั้นคุณเข้าถึง this.datasource.data มันไม่ได้รับการอัปเดต
Rui Marques

5

ใน Angular 9 ความลับคือ this.dataSource.data = this.dataSource.data;

ตัวอย่าง:

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

dataSource: MatTableDataSource<MyObject>;

refresh(): void {
    this.applySomeModif();
    // Do what you want with dataSource

    this.dataSource.data = this.dataSource.data;
}

applySomeModif(): void {
    // add some data
    this.dataSource.data.push(new MyObject());
    // delete index number 4
    this.dataSource.data.splice(4, 0);
}

1
ขอบคุณ! ทำงานให้ฉัน
ebem

4

คุณสามารถอัปเดตข้อมูลของตารางได้อย่างง่ายดายโดยใช้ "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 ฉันไม่ได้ลองรุ่นอื่น


2
ใช่มันใช้ได้สำหรับฉันเป็นปัญหาเกี่ยวกับการอ้างอิงและค่า var การตรวจจับการเปลี่ยนแปลงไม่เห็นการเปลี่ยนแปลงใหม่เพราะคุณต้องอัปเดต
Mayra Rodriguez

สิ่งนี้อาจใช้ได้หาก dataSource เป็นเพียงอาร์เรย์ แต่ไม่ใช่เมื่อ dataSource เป็นวัตถุ MatTableDataSource
Rui Marques

4

ฉันพบปัญหาที่คล้ายกันซึ่งฉันได้เพิ่มบางอย่างลงในแหล่งข้อมูลและไม่ได้โหลดซ้ำ

วิธีที่ง่ายที่สุดที่ฉันพบคือการกำหนดข้อมูลใหม่

let dataSource = ['a','b','c']
dataSource.push('d')
let cloned = dataSource.slice()
// OR IN ES6 // let cloned = [...dataSource]
dataSource = cloned

1
เป๊ะ !! มันตื่น !! ขอบคุณ :)
Nicolas


2

ฉันประสบความสำเร็จในการแก้ปัญหาที่ดีโดยใช้ทรัพยากรสองอย่าง:

รีเฟรชทั้ง dataSource และ paginator:

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

โดยที่ตัวอย่างdataSourceถูกกำหนดไว้ที่นี่:

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

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

8
โปรดเพิ่มคำอธิบายให้กับคำตอบของคุณการโพสต์โค้ดอาจไม่เป็นประโยชน์มากนักและอาจส่งผลให้คำตอบของคุณถูกลบออกไป
TJ Wolschon

1

ในกรณีของฉัน (เชิงมุม 6+) ผมได้รับมาจากการสร้างMatTableDataSource โดยไม่ต้องโทรตามMyDataSourcethis.data = someArray

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

ข้อมูลที่ไม่ปรากฏ

คลาส 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

มีสองวิธีในการดำเนินการเนื่องจากวัสดุเชิงมุมไม่สอดคล้องกันและเอกสารนี้มีเอกสารไม่ดีมาก ตารางวัสดุเชิงมุมจะไม่อัปเดตเมื่อแถวใหม่จะมาถึง น่าแปลกที่มีการบอกว่าเป็นเพราะปัญหาด้านประสิทธิภาพ แต่ดูเหมือนว่าเป็นปัญหาในการออกแบบพวกเขาไม่สามารถเปลี่ยนแปลงได้ ควรคาดว่าตารางจะอัปเดตเมื่อแถวใหม่เกิดขึ้น หากไม่ควรเปิดใช้งานพฤติกรรมนี้โดยค่าเริ่มต้นควรมีสวิตช์เพื่อปิด

อย่างไรก็ตามเราไม่สามารถเปลี่ยน Angular Material ได้ แต่โดยพื้นฐานแล้วเราสามารถใช้วิธีการที่มีเอกสารไม่ดีมากในการทำ:

หนึ่ง - ถ้าคุณใช้อาร์เรย์โดยตรงเป็นแหล่งที่มา:

call table.renderRows()

โดยที่ตารางคือ ViewChild ของ mat-table

ประการที่สอง - หากคุณใช้การเรียงลำดับและคุณสมบัติอื่น ๆ

table.renderRows () ไม่ทำงานอย่างน่าประหลาดใจ เนื่องจากตารางเสื่อไม่สอดคล้องกันที่นี่ คุณต้องใช้แฮ็คเพื่อบอกแหล่งที่มาที่เปลี่ยนไป คุณทำได้ด้วยวิธีนี้:

this.dataSource.data = yourDataSource;

โดยที่ dataSource คือ MatTableDataSource wrapper ที่ใช้สำหรับการเรียงลำดับและคุณสมบัติอื่น ๆ


0

สิ่งนี้ใช้ได้ผลสำหรับฉัน:

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

ไม่ใช่ทางออกที่ดีเนื่องจากสร้างซอร์สใหม่สำหรับตารางและการใช้สิ่งนี้กับคล่องตัว / ซ็อกเก็ตนั้นไม่ได้ผล
Maihan Nijat

0

ฉันคิดว่าMatTableDataSourceวัตถุเชื่อมโยงกับอาร์เรย์ข้อมูลที่คุณส่งผ่านไปยังตัวMatTableDataSourceสร้าง

ตัวอย่างเช่น:

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

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

ดังนั้นเมื่อคุณต้องเปลี่ยนข้อมูล เปลี่ยนแปลงรายการเดิมdataTableและจากนั้นสะท้อนให้เห็นถึงการเปลี่ยนแปลงบนโต๊ะโดยการเรียกวิธีการในการ_updateChangeSubscription()tableDS

ตัวอย่างเช่น:

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

นั่นใช้ได้กับฉันผ่าน Angular 6


4
วิธีนั้นขึ้นต้นด้วยเครื่องหมายขีดล่าง_และคุณเรียกมันว่า?
Stephane

0

สิ่งนี้ใช้ได้ผลสำหรับฉัน:

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


0

ฉันได้ทำการค้นคว้าเพิ่มเติมและพบว่าสถานที่นี้ให้สิ่งที่ฉันต้องการ - รู้สึกสะอาดและเกี่ยวข้องกับการอัปเดตข้อมูลเมื่อรีเฟรชจากเซิร์ฟเวอร์: https://blog.angular-university.io/angular-material-data-table/

เครดิตส่วนใหญ่ไปยังหน้าด้านบน ด้านล่างนี้เป็นตัวอย่างวิธีการใช้ mat-selector เพื่ออัปเดต mat-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);
  }
}

0

หลังจากอ่านตารางวัสดุที่ไม่อัปเดตการอัปเดตข้อมูลโพสต์ # 11638 รายงานข้อบกพร่อง ฉันพบว่าสิ่งที่ดีที่สุด (อ่านวิธีแก้ปัญหาที่ง่ายที่สุด) เป็นไปตามที่ผู้แสดงความเห็นสุดท้าย 'shhdharmen' พร้อมคำแนะนำในการใช้ EventEmitter

สิ่งนี้เกี่ยวข้องกับการเปลี่ยนแปลงเล็กน้อยในคลาสแหล่งข้อมูลที่สร้างขึ้น

เช่น) เพิ่มตัวแปรส่วนตัวใหม่ให้กับคลาสแหล่งข้อมูลของคุณ

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

และที่ที่ฉันพุชข้อมูลใหม่ไปยังอาร์เรย์ภายใน (this.data) ฉันจะปล่อยเหตุการณ์

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

และสุดท้ายเปลี่ยนอาร์เรย์ 'dataMutation' ในวิธี 'เชื่อมต่อ' - ดังต่อไปนี้

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

0

// นี่คือ dataSource
this.guests = [];

this.guests.push ({id: 1, ชื่อ: 'Ricardo'});

// รีเฟรช dataSource this.guests = Array.from (this.guest);


0
npm install @matheo/datasource

ฉันเปิดตัวไลบรารีที่มีวัตถุประสงค์เพื่อเป็นแหล่งข้อมูลวัสดุอย่างเป็นทางการในอนาคตโดยรองรับสตรีมอินพุตประเภทใดก็ได้ (การเรียงลำดับการแบ่งหน้าตัวกรอง) และการกำหนดค่าบางอย่างพร้อมการดีบักเพื่อดูว่ามันทำงานอย่างไรในขณะที่คุณกำลังเขียนโค้ด

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

คุณสามารถดูการสาธิต StackBlitz และข้อมูลเพิ่มเติมได้ที่นี่:
https://medium.com/@matheo/reactive-datasource-for-angular-1d869b0155f6

เรายินดีที่จะรับฟังความคิดเห็นของคุณและสนับสนุนกรณีการใช้งานของคุณหากจำเป็น
ขอให้สนุกกับการเขียนโค้ด!


0

ฉันได้ลอง ChangeDetectorRef, Subject และ BehaviourSubject แล้ว แต่สิ่งที่เหมาะกับฉัน

dataSource = [];
this.dataSource = [];
 setTimeout(() =>{
     this.dataSource = this.tableData[data];
 },200)

เกิดอะไรขึ้นที่นี่? ฉันรู้สึกว่าเกิดข้อผิดพลาดในการตั้งชื่อตัวแปร
ChumiestBucket
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.