Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use angular2 material Dialog to block for canDeactivate

I am successfully using canDeactivate to provide a warning message if a user navigates from a page with a dirty form:

The code that I am using is here:

    is_submit = false;
   canDeactivate() {
       //https://scotch.io/courses/routing-angular-2-applications/candeactivate
        if (this.myForm.dirty == true && this.is_submit==false){
            return window.confirm('Discard changes?');
        } //end if
        return true
    } // end  canDeactivate

This is where I got the code:

https://scotch.io/courses/routing-angular-2-applications/candeactivate

However I would like to use a angular2 Dialog. Here is my code:

    //ts for the main component

    is_submit = false;
   canDeactivate() {
        if (this.myForm.dirty == true && this.is_submit==false){
            const config = new MdDialogConfig();
            config.disableClose=true;
            let dialogRef = this.dialog.open(DialogCanDeactive,config);
            dialogRef.afterClosed().subscribe(result => {
                if (result=='cancel'){
                    return false;
                } 
                if (result=='save'){
                    return true;
                } 
                if (result=='discard'){
                    return true;
                } 
            }); //end dialogRef
        } //end if
        return true
    }

 ///Code for the dialog

@Component({
  selector: 'can_deactive_dialog',
  template: `
<div>
    <button md-raised-button (click)="dialogRef.close('cancel')">Cancel</button>
    <button md-raised-button (click)="dialogRef.close('save')">Save Changes</button>
    <button md-raised-button (click)="dialogRef.close('discard')">Discard Changes</button>
</div>
`,
})
export class DialogCanDeactive {


  constructor(public dialogRef: MdDialogRef<DialogCanDeactive>) {} //end constructor

}

What happens when i navigate away is this:

1) I go to the page where a navigate

2) the Dialog then show..

How to have the Dialog block like the below code?

    window.confirm('Discard changes?')
like image 793
Tampa Avatar asked Jul 22 '17 06:07

Tampa


3 Answers

canDeactivate method can also return a Promise or Observable. You should return that and resolve the promise or emit a value on the observable with the result that you want.

In your specific example you can return the observable from the afterClosed method instead of subscribing to it, and just map it to a boolean:

return dialogRef.afterClosed().map(result => {
                if (result=='cancel'){
                    return false;
                } 
                if (result=='save'){
                    return true;
                } 
                if (result=='discard'){
                    return true;
                } 
            }).first();

Also I would move out this logic from the guard, for example in the component and just call a method from there.

like image 183
Adrian Fâciu Avatar answered Oct 20 '22 14:10

Adrian Fâciu


 Nothing more just do it

**Guard**

import { Injectable } from '@angular/core';
import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } 
from '@angular/router';
import { Observable} from 'rxjs';
import { ExampleComponent } from '../components/example.component';
import { MatDialog } from '@angular/material/dialog'; 

@Injectable({
  providedIn: 'root'
})
export class ConfirmationDeactivateGuard implements CanDeactivate<ExampleComponent> {
  constructor(private dialog: MatDialog,
    private router: Router){}
    canDeactivate(
      component: ExampleComponent,
      route: ActivatedRouteSnapshot,
      state: RouterStateSnapshot
    ): Observable<boolean> {
      return component.confirmationOnRouteChange();
  }
}

**In Your Component** //ExampleComponent.component.ts

confirmationOnRouteChange() {
        const message = "Do you want to Leave ?"
        const dialogRef = this.matDialog.open(ConfirmationComponent,{
            width: '400px',
            data: { message }
        })
        return dialogRef.afterClosed();
    }
like image 31
Chandrashakhar Kumar Avatar answered Oct 20 '22 14:10

Chandrashakhar Kumar


Updated version for RXJS 6+ :

return dialogRef.afterClosed().pipe(map(result => {
    if (result === 'cancel') {
        return false;
    }
    if (result === 'save') {
        return true;
    }
    if (result === 'discard') {
        return true;
    }
}), first());

see https://github.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/v6/migration.md

Here in particular : https://github.com/ReactiveX/rxjs/blob/master/docs_app/content/guide/v6/migration.md#howto-convert-to-pipe-syntax

like image 4
Florian Motteau Avatar answered Oct 20 '22 16:10

Florian Motteau