我正在使用一个垫子表列出用户选择的语言的内容。他们还可以使用对话框面板添加新的语言。在他们添加了一门语言并返回之后。我希望刷新数据源以显示他们所做的更改。

我通过从服务获取用户数据并在刷新方法中将其传递到数据源来初始化数据存储。

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
  }

}

因此,我尝试调用一个刷新方法,我从后端再次获得用户,然后重新初始化数据源。然而,这并没有起作用,没有发生任何变化。


当前回答

由于您正在使用MatPaginator,您只需要对分页器做任何更改,这将触发数据重新加载。

简单的技巧:

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

这将页面大小更新为当前页面大小,因此基本上没有任何变化,除了也调用私有_emitPageEvent()函数,从而触发重新加载表。

其他回答

似乎您的refresh()函数正在适当地向teachDS数据源添加一个新实例。但是,表没有被更新,因为它没有被指示这样做。

你可以指示Angular使用ChangeDetectorRef服务监控数据源的变化,并在必要时更新表。

ChangeDetectorRef服务必须首先注入到你的组件中:

import { ChangeDetectorRef } from '@angular/core';

constructor(
            private authService: AuthService, 
            private dialog: MatDialog, 
            private changeDetectorRef: ChangeDetectorRef
) { }

然后,在refresh()函数中刷新数据源后,你可以指示Angular检查更改并通过changeDetectorRef上的detectChanges()方法更新表:

refresh() {
  this.authService.getAuthenticatedUser().subscribe((res) => {
    this.user = res;
    this.teachDS = new LanguageDataSource(this.user.profile.languages.teach);
    this.changeDetectorRef.detectChanges();  // <-- Tell Angular to check for changes
  });
}

因此,应该更新表以反映数据源的更改。

我利用两种资源获得了一个很好的解决方案:

刷新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;
    ...

当你设置你的数据源。Ts文件,而不是使用一个简单的数组的数据使用一个主题和getter/setter的数据,如下所示:

 dataStream = new BehaviorSubject<DataSourceItem[]>(EXAMPLE_DATA);
 set data(v: DataSourceItem[]) { this.dataStream.next(v); }
 get data(): DataSourceItem[] { return this.dataStream.value; }

然后在connect()函数中使用dataStream主题,如下所示:

return merge(this.dataStream, this.paginator.page, this.sort.sortChange)

所以现在当你改变数据源时。数据数组…像这样:

this.dataSource.data = ['my','new','item']

它将触发setter中的this.dataStream.next(v), connect()函数将正确更新您的表。

完整的工作示例可以在这里找到: https://stackblitz.com/edit/angular-material2-issue-yzhsml?file=app%2Fdata-table-datasource.ts

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

好吧,我遇到了一个类似的问题,我向数据源添加了一些东西,但它没有重新加载。

我发现最简单的方法就是重新分配数据

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