Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 8 MatDialog await the result to continue

Tags:

angular

dialog

I'm parsing excel sheets but If there are more than just 1 sheet the user needs to choose. I want to do this with a dialog and the function needs to wait until the result is there.

My code:

app.component.ts:

onFileSelected(file: File): void {
       const reader: FileReader = new FileReader();
       reader.onload = async (e: any) => {
         // read workbook
         const bstr: string = e.target.result;
         const wb: XLSX.WorkBook = XLSX.read(bstr, {
           type: "binary",
           sheetRows: 101
         });

         this.sheetNames = wb.SheetNames;

         if (this.sheetNames.length > 1) {
           console.log("größer eins");
           await this.openDialog();
         }
         // grab first sheet
         const wsname: string = wb.SheetNames[this.sheetIndex];
         const ws: XLSX.WorkSheet = wb.Sheets[wsname];

         this.data = XLSX.utils.sheet_to_json(ws, { header: 0 });
       };
       reader.readAsBinaryString(this.uploadComponent.file);
}

openDialog(): void {
 const dialogRef = this.chooseSheetDialog.open(ChooseSheetDialogComponent, {
   width: "500px",
   data: { sheets: this.sheetNames }
 });

 dialogRef.afterClosed().subscribe(result => {
   console.log("The dialog was closed " + result);
   this.sheetIndex = result;
 });
}

It's a shortened form.

The dialog.ts:

 export class ChooseSheetDialogComponent {
   selectFormControl = new FormControl("", Validators.required);
   constructor(
     @Inject(MAT_DIALOG_DATA) private data: any,
     public dialogRef: MatDialogRef<ChooseSheetDialogComponent>
   ) {}

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

dialog.html:

<h1 mat-dialog-title>Wähle aus</h1>
<div mat-dialog-content>
<p>Es existieren mehrere Arbeitsblätter / Tabellen. Bitte wähle.</p>
<mat-form-field>
 <mat-label>Favorite sheet</mat-label>
 <mat-select required [formControl]="selectFormControl">
   <mat-option *ngFor="let sheet of data.sheets" [value]="sheet">
     {{sheet}}
   </mat-option>
 </mat-select>
 <mat-error *ngIf="selectFormControl.hasError('required')">
   This field is required
 </mat-error>
</mat-form-field>
</div>
<div mat-dialog-actions>
<button mat-button (click)="onNoClick()">No Thanks</button>
<button mat-button [mat-dialog-close]="selectFormControl.value" cdkFocusInitial>Ok</button>
</div>

But yes however await this.openDialog(); does not work. Error in the browser:

ERROR Error: Uncaught (in promise): TypeError: Cannot read property '!ref' of undefined
TypeError: Cannot read property '!ref' of undefined
    at AppComponent.getExcelHeaderRow (app.component.ts:121)
like image 636
CptDayDreamer Avatar asked Jan 07 '20 01:01

CptDayDreamer


1 Answers

You can use toPromise function in order to have a Promise-oriented logic. Also, the function must return a Promise so that you can use await later:

async openDialog(): Promise<number> {
 const dialogRef = this.chooseSheetDialog.open(ChooseSheetDialogComponent, {
   width: "500px",
   data: { sheets: this.sheetNames }
 });

 return dialogRef.afterClosed()
   .toPromise() // here you have a Promise instead an Observable
   .then(result => {
      console.log("The dialog was closed " + result);
      this.sheetIndex = result;
      return Promise.resolve(result); // will return a Promise here
   });
}

Then, your onFileSelected function can use await as follows:

async onFileSelected(file: File): void {
    const result = await this.openDialog(); // waiting here
    console.log('result', result); // you got the value
}

Also, I wrote a working sample here. Don't forget to open the browser's console to see the results.

I hope it helps!

like image 68
luixaviles Avatar answered Sep 30 '22 04:09

luixaviles