如何使用观察到的动态更新角度材料表

时间:2019-04-14 14:24:22

标签: angular

我希望每当appUsers: AppUser[]中所有AppUserService的全局数组更新时,Angular Material Table都会动态更新。

我知道,如果表是用*ngFor构造的,那么我所知道的解决方案就可以正常工作。但是,它与Angular Material Table的工作方式有所不同。

Angular Material的official documentation说:

  

向表提供数据的另一种方法是传递一个Observable流,该流在每次更改时都会发出要呈现的数据数组。该表将侦听此流,并在每次发出新的数据数组时自动触发对行的更新。

这是我想追求的,但是我找不到真正的例子。


AdminComponent保留了我表的数据源。

export class AdminComponent implements OnInit, OnDestroy {

  dataSource = new MatTableDataSource<AppUser>();
  private getAppUsersSubscription: Subscription;

  columnsToDisplay = ['userName', 'lastLogin', 'changePassword', 'deleteCustomer'];

  constructor(
    private appUserService: AppUserService,
    private newCustomerDialog: MatDialog) { }

  ngOnInit() {
    this.getAppUsersSubscription = this.appUserService.getAppUsers().subscribe(
      (response: AppUser[]) => {
        this.dataSource.data = response;
      },
      error => {
        console.log(error);
      }
    );
  }

  newAppUser() {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.autoFocus = true;
    dialogConfig.disableClose = true;

    this.newCustomerDialog.open(NewAppUserComponent, dialogConfig);
  }

  ngOnDestroy() {
    this.getAppUsersSubscription.unsubscribe();
  }
}

admin.component.html这是视图。

<div class="container-fluid">
    <div class="row">
        <div class="col-12 col-sm-12 col-md-6 col-lg-6 new">
            <button class="btn btn-primary new-button" (click)="newAppUser()">New Customer</button>
        </div>
        <div class="col-12 col-sm-12 col-md-6 col-lg-6 new">
            <button class="btn btn-primary new-button">New Setting</button>
        </div>
    </div>
    <mat-tab-group mat-stretch-tabs [dynamicHeight]="true">
        <mat-tab label="Customers">
            <table mat-table [dataSource]="dataSource">
                <ng-container matColumnDef="userName">
                    <th mat-header-cell *matHeaderCellDef> Customer </th>
                    <td mat-cell *matCellDef="let appUser"> {{ appUser.userName }} </td>
                </ng-container>

                <ng-container matColumnDef="lastLogin">
                    <th mat-header-cell *matHeaderCellDef> Last Login </th>
                    <td mat-cell *matCellDef="let appUser"> {{ appUser.lastLogin | date: 'yyyy-MM-dd HH:mm' }} </td>
                </ng-container>

                <ng-container matColumnDef="changePassword">
                    <th class="text-center" mat-header-cell *matHeaderCellDef> Change Password </th>
                    <td class="clickable" mat-cell *matCellDef="let appUser"><i class="fas fa-key"></i></td>
                </ng-container>

                <ng-container matColumnDef="deleteCustomer">
                    <th class="text-center" mat-header-cell *matHeaderCellDef> Delete Customer </th>
                    <td class="clickable" mat-cell *matCellDef="let appUser"><i class="fas fa-trash"></i></td>
                </ng-container>

                <tr mat-header-row *matHeaderRowDef="columnsToDisplay"></tr>
                <tr mat-row *matRowDef="let myRowData; columns: columnsToDisplay"></tr>
            </table>
        </mat-tab>
        <mat-tab label="Settings">

        </mat-tab>
    </mat-tab-group>
</div>


NewAppUserComponent是对话框窗口组件,在其中创建新的AppUser

export class NewAppUserComponent implements OnInit {

  newAppUserForm: FormGroup;
  submitted = false;
  appUser: AppUser;

  constructor(
    public dialogRef: MatDialogRef<NewAppUserComponent>,
    private formBuilder: FormBuilder,
    private appUserService: AppUserService
  ) {
    this.appUser = new AppUser();
  }

  ngOnInit() {
    this.newAppUserForm = this.formBuilder.group({
      userName: ['', Validators.required],
      password: ['', [Validators.required, Validators.minLength(6)]],
      confirmPassword: ['', Validators.required]
    });
  }

  get f() {
    return this.newAppUserForm.controls;
  }

  onSubmit() {
    this.submitted = true;

    this.appUser.userName = this.f.userName.value;
    this.appUser.password = this.f.password.value;

    this.appUserService.postAppUser(this.appUser)
      .pipe(first())
      .subscribe(
        data => {
          this.dialogRef.close();
        },
        error => {
          console.log(error);
        }
      )
  }

  onCancel() {
    this.dialogRef.close();
  }
}


AppUserServiceAppUser发布到API并在一切顺利的情况下收到副本。我将新创建的AppUser推送到appUsers: AppUser[]的全局数组中。我希望此更改反映在AdminComponent中的表中。

export class AppUserService {

  public appUsers: AppUser[];
  private appUsersSubject: BehaviorSubject<AppUser[]>;
  public appUsersObservable: Observable<AppUser[]>;

  constructor(private repository: RepositoryService) {
    this.appUsers = new Array<AppUser>();
    this.appUsersSubject = new BehaviorSubject<AppUser[]>(null);
    this.appUsersObservable = this.appUsersSubject.asObservable();
  }

  getAppUsers(): Observable<AppUser[]> {
    let api: string = "api/appuser";
    return this.repository.get(api).pipe(
      map(response => {
        this.appUsers = Object.assign(this.appUsers, response);
        this.appUsersSubject.next(this.appUsers);
        return this.appUsers;
      })
    );
  }

  postAppUser(appUser: AppUser): Observable<AppUser> {
    let api: string = "api/appuser";
    return this.repository.post(api, appUser).pipe(
      map(response => {
        let appUser = new AppUser();
        appUser = Object.assign(appUser, response);
        // Add new AppUser to AppUsers array
        this.appUsers.push(appUser);
        return appUser;
      })
    )
  }
}

2 个答案:

答案 0 :(得分:0)

尝试以下代码将dataSource.data数组重置为空数组,然后将响应数组附加到该数组以触发更改检测。

 ngOnInit() {
    this.getAppUsersSubscription = this.appUserService.getAppUsers().subscribe(
      (response: AppUser[]) => {
        this.dataSource.data = [];
        this.dataSource.data.push(...response);
      },
      error => {
        console.log(error);
      }
    );
  }

答案 1 :(得分:0)

通过添加以下内容解决了问题。

admin.component.html在这里我添加了对MatTable的引用,名为#appUserTable,并将该引用传递给了(click)="newAppUser(appUserTable)

<table mat-table #appUserTable [dataSource]="dataSource">
</table>

...

<button class="btn btn-primary new-button" (click)="newAppUser(appUserTable)">New Customer</button>

admin.component.ts在这里,我获取引用并将其传递给new-appuser.component.ts

newAppUser(appUserTable: MatTable<AppUser>) {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.autoFocus = true;
    dialogConfig.disableClose = true;
    dialogConfig.data = { appUserTable }

    this.newCustomerDialog.open(NewAppUserComponent, dialogConfig);
  }

new-appuser.component.ts现在,对话框中有引用。当我收到来自API调用的成功响应时,我运行this.appUserTable.renderRows();

appUserTable: MatTable<AppUser>;

  constructor(
    @Inject(MAT_DIALOG_DATA) public data,
  ) {
    this.appUserTable = data.appUserTable;
  }

...

this.appUserService.postAppUser(this.appUser)
      .pipe(first())
      .subscribe(
        data => {
          this.dialogRef.close();
          this.appUserTable.renderRows();
        },
        error => {
          console.log(error);
        }
      )