Angular Material对话框:如何在父组件中更改注入的数据时更新它们?

时间:2018-05-07 13:26:57

标签: angular dialog modal-dialog angular-material

将数据注入到材质对话框中效果很好,但如果这些数据在父/开启组件中发生更改(例如来自(WAMP)订阅),如何自动更新这些数据?

[更新]
我创建了一个最小版本来试验行为:https://stackblitz.com/edit/angular-njh44v?embed=1&file=src/app/app.component.ts
打开右下方的控制台,然后单击带有数字的灰色框。您看到对话框获取当前编号,之后不再更新。
[/更新]

[更新2]
基于Jusmpty的第二个想法,这个接缝一见钟面(即使对话框在数据到达后第一次显示/更新): https://stackblitz.com/edit/angular-thd34f?embed=1&file=src/app/app.component.ts
[/更新]

具体案例如下:

  • 有一个区域组件订阅WAMP服务并获取包含部分的所有数据。这将使用* ngFor绘制所有部分 文件 area.component.ts
  • 每个部分都有一个自己的组件,显示一些数据。如果订阅中的数据发生更改,则视图会针对每个/所有部分正确并自动更新。
    文件 part.component.ts part.component.html
  • 在每个部分上,单击将打开一个对话框,其中显示更多数据。
    文件 part-details-dialog.component.ts part-details-dialog.component.html

在最后一个操作/步骤发生当前数据显示(注入)的问题,但如果订阅数据中的某些内容发生更改,则不再更新。

area.component.ts

@Component({
  selector: 'app-area',
  template: '<app-part *ngFor="let part of plan" [partData]="part"></app-part>'
})
export class AreaComponent {

  plan = [];

  planasync$ = this.wampService
    .topic('sendplan')
    .subscribe(
      res => {
        let tm = new TableMap();
        this.plan = tm.tableToMap(res.argskw).filter((m) => m.area === 1);
      },
      err => console.log("res err", err),
      () => console.log("res complete"));

  constructor(private wampService: WampService) { }
}

part.component.ts

import { PartDetailsDialogComponent } from './part-details-dialog/part-details-dialog.component';

@Component({
  selector: 'app-part-details',
  templateUrl: './part.component.html'
})
export class PartComponent {
  @Input() partData: any;

  constructor(public dialog: MatDialog) {}

  openDetailsDialog(): void {
    let dialogRef = this.dialog.open(PartDetailsDialogComponent, {
      width: '650px',
      height: '400px',
      data: {
        partData: this.partData
      }
    });
  }
}

part.component.html

<mat-card (click)="openDetailsDialog()">
  <mat-card-title>Nr: {{ partData.partNr }}</mat-card-title>
  <mat-card-content>
      <div>Current speed: {{ partData.speed }}</div>
  </mat-card-content>
</mat-card>

部分细节-dialog.component.ts

@Component({
  selector: 'app-part-details-dialog',
  templateUrl: './part-details-dialog.component.html'
})
export class PartDetailsDialogComponent {

  constructor(public dialogRef: MatDialogRef<PartDetailsDialogComponent>, @Inject(MAT_DIALOG_DATA) public data: any) { }

  onNoClick(): void {
    this.dialogRef.close();
  }
}

部分细节-dialog.component.html

<h1 mat-dialog-title>Part Details for Nr. {{ data.partData.partNr }}</h1>
<div mat-dialog-content>
  <div>Current speed details: {{ data.partData.speed }}</div>
</div>
<div mat-dialog-actions>
  <button mat-button (click)="onNoClick()">Cancel</button>
  <button mat-button [mat-dialog-close]="data.animal" cdkFocusInitial>Ok</button>
</div>

3 个答案:

答案 0 :(得分:13)

您可以仅更改组件实例的data,而不是这样做:

this.dialogRef.componentInstance.data = {numbers: value};

此处的示例: https://stackblitz.com/edit/angular-dialog-update

答案 1 :(得分:2)

目前我有两种方式可以想到,我也不喜欢,但嘿......

两种方式都涉及通过数据向对话框发送observable。

  1. 您可以将零件的observable传递给零件组件,然后将数据中的observable传递给对话框。然后,该对话框可以订阅observable并以这种方式获取更新。
  2. AreaComponent

    @Component({
      selector: 'app-area',
      template: '<app-part *ngFor="let part of planAsync$ | async; i as index" [partData]="part" [part$]="part$(index)"></app-part>'
    })
    export class AreaComponent {
    
      plan = [];
    
      constructor(private wampService: WampService) {
      }
    
      part$(index) {
        return this.planAsync$
          .map(plan => plan[index]);
      }
    
      get planAsync$() {
        return this.wampService
          .topic('sendplan')
          .map(res => {
            let tm = new TableMap();
            return tm.tableToMap(res.argskw).filter((m) => m.area === 1);
          });
      }
    }
    

    零件组件

    @Component({
      selector: 'app-part-details',
      templateUrl: './part.component.html'
    })
    export class PartComponent {
      @Input() partData: any;
      @Input() part$
    
      constructor(public dialog: MatDialog) {}
    
      openDetailsDialog(): void {
        let dialogRef = this.dialog.open(PartDetailsDialogComponent, {
          width: '650px',
          height: '400px',
          data: {
            partData: this.partData,
            part$: this.part$
          }
        });
      }
    }
    

    当然,问题是,如果你只是直接访问数据,那么甚至传递partData是多么有用。

    1. 另一种方式要求您只修改零件组件,但您必须创建一个主题,将更改提供给组件接收的零件。我真的不喜欢制作主题,特别是如果数据最初来自一个可观察的,但无论如何:
    2. 零件组件

      @Component({
        selector: 'app-part-details',
        templateUrl: './part.component.html'
      })
      export class PartComponent, OnChanges {
        @Input() partData: any;
      
        private Subject part$ = new Subject();
      
        constructor(public dialog: MatDialog) {}
      
        ngOnChanges(changes){
          this.part$.next(changes['partData']);    
        }
      
        openDetailsDialog(): void {
          let dialogRef = this.dialog.open(PartDetailsDialogComponent, {
            width: '650px',
            height: '400px',
            data: {
              partData: this.partData,
              part$: this.part$
            }
          });
        }
      }
      

      最后,要访问数据,您可以将html更改为

      对话框HTML

      <div *ngIf="(data.part$ | async) as part">
        <h1 mat-dialog-title>Part Details for Nr. {{ part.partNr }}</h1>
        <div mat-dialog-content>
          <div>Current speed details: {{ part.speed }}</div>
        </div>
        <div mat-dialog-actions>
          <button mat-button (click)="onNoClick()">Cancel</button>
          <button mat-button [mat-dialog-close]="data.animal" cdkFocusInitial>Ok</button>
        </div>
      </div>
      

      或者您可以在对话框组件中订阅observable,并从那里提供数据

答案 2 :(得分:1)

一个组件托管一个对话框。 如果组件数据发生更改,则对话框数据也应更改。 为此,鹏辉的第一个回答正在起作用。

如果该对话框必须根据数据更改执行某些操作,则没有(事件)触发器告诉对话框数据已更改。

为此,解决方案是(它也适用于这个问题):

第一步:声明类变量dialogRef:MatDialogRef

step2:在Dialog组件中创建一个方法xMethod()

step3:保留分配给 this.dialogRef 的对话框引用

步骤 4:每当托管组件想要更改组件中以下行的对话框数据时:

  if (this.dialogRef  && this.dialogRef.componentInstance) {
       this.dialogRef.componentInstance.xMethod( data);
  }

步骤 5:检查对话框中的 xMethod() 是否被调用,并在来自组件的数据更改事件上编写您想做的任何事情。

请检查此工作代码:

https://stackblitz.com/edit/angular-arvuho?embed=1&file=src/app/app.component.ts