Reputation: 78234
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?')
Upvotes: 10
Views: 3779
Reputation: 11
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();
}
Upvotes: 1
Reputation: 3714
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
Upvotes: 4
Reputation: 12552
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.
Upvotes: 13