Диалоговое окно Angular Material: Как обновить введенные данные при их изменении в родительском компоненте? - PullRequest
0 голосов
/ 07 мая 2018

Внедрение данных в диалоговое окно материала работает хорошо, но как может быть способ автоматического обновления этих данных, если они изменяются в родительском / открывающем компоненте (например, из подписки (WAMP))?

[Update]
Я разработал минимальную версию, чтобы проверить, как это выглядит: https://stackblitz.com/edit/angular-njh44v?embed=1&file=src/app/app.component.ts
Откройте консоль в нижней правой части и нажмите на серое поле с цифрами. Вы видите, что диалоговое окно получает текущий номер и больше не обновляется после этого.
[/ Update]

[Обновление 2]
Основываясь на второй идее Jusmpty, это работает с первого взгляда (даже если диалог показывает / обновляет в первый раз после поступления данных): https://stackblitz.com/edit/angular-thd34f?embed=1&file=src/app/app.component.ts
[/ Update]

Конкретный корпус выглядит так:

  • Существует компонент area , который подписывается на услугу 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>

Ответы [ 2 ]

0 голосов
/ 18 сентября 2018

Вместо этого вы можете просто изменить data экземпляра компонента, например так:

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

Пример здесь: https://stackblitz.com/edit/angular-dialog-update

0 голосов
/ 14 мая 2018

В данный момент я могу думать о двух способах, но мне они тоже не очень нравятся, но эй ...

Оба способа предполагают отправку наблюдаемого в диалог через данные.

  1. Можно передать наблюдаемую часть детали компоненту детали, а затем передать наблюдаемое в данных в диалоговое окно. Диалог мог бы тогда подписаться на наблюдаемое и получать обновления таким образом.

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. Другой способ требует, чтобы вы просто изменили компонент детали, но вам нужно будет создать тему, в которую вы будете вносить изменения в деталь, которую получает компонент. Я не очень люблю делать предметы, особенно если данные уже исходят из наблюдаемой, но все равно:

Компонент детали

@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>

Или вы можете подписаться на наблюдаемый в диалоговом компоненте и предоставить данные оттуда

...