首页 文章

角度材质 - 如何刷新数据源(mat-table)

提问于
浏览
46

我使用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
  }

}

所以我试图调用一个刷新方法,我再次从后端获取用户,然后重新初始化数据源 . 但是这不起作用,不会发生任何变化 .

14 回答

  • 11

    最好的方法是在Datasource实现中添加一个额外的observable .

    你应该已经使用 Observable.merge 订阅可观,其中包括了paginator.page,sort.sortChange等阵列connect方法,您可以添加一个新的课题,以这一点,接下来请它时,你需要引起刷新 .

    这样的事情:

    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()方法中,并从组件中的数据源实例和其他适当的技术中调用它 .

  • 0

    在接收到新数据后,在 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();
        });
      }
    }
    
  • 25

    我不知道在创建问题时是否需要 ChangeDetectorRef ,但现在这已经足够了:

    import { MatTableDataSource } from '@angular/material/table';
    
    // ...
    
    dataSource = new MatTableDataSource<MyDataType>();
    
    refresh() {
      this.myService.doSomething().subscribe(data: MyDataType[] => {
        this.dataSource.data = data;
      }
    }
    
  • 1

    所以对我来说,没有人能够很好地回答我遇到的问题,这个问题几乎与@Kay相同 . 对我来说这是关于排序,排序表不会发生垫子的变化 . 我的目的是这个答案,因为它是我通过搜索谷歌找到的唯一主题 . 我正在使用Angular 6 .

    如上所述here

    由于表优化了性能,因此不会自动检查数据数组的更改 . 相反,当在数据数组上添加,删除或移动对象时,可以通过调用其renderRows()方法来触发对表的呈现行的更新 .

    因此,您只需在refresh()方法中调用renderRows()即可显示更改 .

    有关集成,请参见here .

  • 0

    由于您使用的是MatPaginator,因此您只需要对paginator进行任何更改,这会触发数据重新加载 .

    简单的技巧:

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

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

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

    在添加或删除特定行的操作下方添加此行 .

    refresh() {
      this.authService.getAuthenticatedUser().subscribe((res) => {
        this.user = new MatTableDataSource<Element>(res);   
      });
    }
    
  • 34
    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);   
        });
      }
    }
    
  • 10

    在我的情况下(Angular 6),我继承自 MatTableDataSource 以创建 MyDataSource . Without callingthis.data = someArray 之后

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

    数据 not displayed

    class 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
    
  • 6

    这对我有用:

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

    我认为 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与我合作的 .

  • 2

    这对我有用:

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

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

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

    您可以使用“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中对我有效,我没有尝试另一个版本 .

  • 0

    您可以使用数据源连接功能

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

    像这样 . 'data'是数据表的新值

相关问题