Injecting data to a material dialog is working well, but how can be a way to automatically update these data if they change in the parent / opener component (coming from a (WAMP) subscription for example)?
[Update]
I crated a minimal version to try out how the behavior is: https://stackblitz.com/edit/angular-njh44v?embed=1&file=src/app/app.component.ts
Open the console on the bottom right side and click on the grey box with the numbers. You see that the dialog gets the current number and does no more update after that.
[/Update]
[Update 2]
Based on the second idea of Jusmpty, this seams to work at first sight (even if the dialog shows / updates the first time after data arrive):
https://stackblitz.com/edit/angular-thd34f?embed=1&file=src/app/app.component.ts
[/Update]
The concrete case looks like this:
And on this last action / step occurs the issue where the current data are showing (injecting) but no more updated if something in the subscribed data changes.
@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) { }
}
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
}
});
}
}
<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>
@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();
}
}
<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>
You can just change data
of the component instance, like this:
this.dialogRef.componentInstance.data = {numbers: value};
Example here: https://stackblitz.com/edit/angular-dialog-update
There are 2 ways I can think of at the moment, I don't really like either, but hey...
Both ways involve sending an observable to the dialog through the data.
@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$
}
});
}
}
Of course the question then is how useful it is to even pass partData along, if you could just access the data directly anyway.
@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$
}
});
}
}
finally, to access the data, you could change the html to
<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>
Or you could subscribe the to observable in the dialog component, and provide the data from there
One component is hosting a dialog. If the component data is changed then the dialog data also should change. For this, first answer by Penghui is working.
In case if that dialog has to do some action based on the data change, there is no (event) trigger telling that dialog data has been changed.
for this the solution is (It will work for this question also):
Step 1: declare class variable dialogRef: MatDialogRef
step2: in Dialog component crate a method xMethod()
step3: keep the dialog reference assigned to this.dialogRef
step4: whenever hosting component wants to change dialog-data use below lines in the component:
if (this.dialogRef && this.dialogRef.componentInstance) {
this.dialogRef.componentInstance.xMethod( data);
}
step5: check xMethod() in dialog is called and write anything you want to do on the data change event from the component.
pls check this working code:
https://stackblitz.com/edit/angular-arvuho?embed=1&file=src/app/app.component.ts
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With