Search code examples
angularasynchronousangular-materialmodal-dialogcandeactivate

How to make Angular canDeactivate Service wait for Modal Dialog response?


I have a function inside the component to check if I can leave the route by evaluating a form status. If the status matches to a contidition which I need to ask to leave the route, it shows up a dialog to confirm or cancel. I call this function inside my canDeactivate service, but it triggers the response before waiting for the dialog confirmation.

I've already put a console.log inside the canDeactivate service with the component's function. When a confirmation is not required, it shows true as expected. But on the other hand, when a confirmation is required, it shows undefined before the dialog box appears.

canDeactivateService.ts

@Injectable()
export class ProdutosDeactivateGuard implements CanDeactivate<ExampleComponent> {

  canDeactivate(
      component: ExampleComponent,
      route: ActivatedRouteSnapshot,
      state: RouterStateSnapshot
    ): boolean {
      return component.checkStatus();
  }
}

example-component.ts

checkStatus() {
    if (!this.form.pristine && this.form.touched) {
      const dialogRef = this.dialog.open(DeactivateDialogComponent);
      dialogRef.afterClosed().subscribe(result => {
        if (result === 'true') {
          return true;
        } else {
          return false;
        }
      });
    } else {
      return true;
    }
  }
}

I'd like the service to wait for the confirmation. How could I do this?


Solution

  • Have you tried returning an observable? as I see in your code afterClosed() returns one.

    For example:

    @Injectable() export class ProdutosDeactivateGuard implements CanDeactivate {

    canDeactivate(
          component: ExampleComponent,
          route: ActivatedRouteSnapshot,
          state: RouterStateSnapshot
        ): Observable<boolean> {
          return component.checkStatus();
      }
    }
    
    checkStatus() {
        if (!this.form.pristine && this.form.touched) {
          const dialogRef = this.dialog.open(DeactivateDialogComponent);
          return dialogRef.afterClosed().pipe(map(result => {
            return result === 'true';
          }));
        } else {
          return of(true);
        }
      }
    }