DEV Community

Cover image for Implementing custom confirmation modal for canDeactivate
Nikhil Dhawan for This is Angular

Posted on

Implementing custom confirmation modal for canDeactivate

Hi all, in this article, we will discuss what canDeactivate means and how to have a custom confirmation modal implemented based on our app theme.

canDeactivate Router Guard

In Angular we get in build support for the routes we define to have implementation for canDeactivate guard which is how we can restrict the user from moving away from the view when some work is in progress on the current view. Example User is making an edit on his profile page and didn't click on the save button so at that time if we have implemented the router guard for canDeactivate, the user will be asked for the confirmation.
A typical implementation for the canDeactivate looks like

canDeactivate(
    component: Component,
    currentRoute: ActivatedRouteSnapshot,
    currentState: RouterStateSnapshot,
    nextState?: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    return true;
  }
Enter fullscreen mode Exit fullscreen mode

So the thing to take care of here is that what does this function expects to be returned. We can have the exact value of true and false or even an observable or promise which will give true or false or UrlTree or direct UrlTree. So whenever you are implementing this make sure to have the return type which matches the above.

Working Example

So let us see how we can practically implement this guard. We can start with creating the guard service file, you can use Angular CLI to create one by the command

ng g guard custom-guard
Enter fullscreen mode Exit fullscreen mode

Here we will get the options to implement different router guards available
image
But here as we are discussing canDeactivate, we will select that and proceed.
So here is the use case, we have 2 components and we will have router guard implemented on comp1 and when the user is trying to move from comp1 to comp2.
Complete example can be seen on Stackblitz
For code used in comp1, comp2 and confirm-modal it can be referred, here I will talk about code used in route guard.

export class ConfirmguardGuard implements CanDeactivate<Comp1Component> {
  canDeactivate(
    component: Comp1Component,
    currentRoute: ActivatedRouteSnapshot,
    currentState: RouterStateSnapshot,
    nextState?: RouterStateSnapshot
  ):
    | Observable<boolean | UrlTree>
    | Promise<boolean | UrlTree>
    | boolean
    | UrlTree {
    console.log('deactivate');
    let subject = new Subject<boolean>();
    component.openDialog();
    subject = component.subject;
    return subject.asObservable();
  }
}
Enter fullscreen mode Exit fullscreen mode

and in routes array object use as

const routes: Routes = [
  {
    path: 'comp1',
    canDeactivate: [ConfirmguardGuard],
    component: Comp1Component,
  },
  { path: 'comp2', component: Comp2Component },

  { path: '', redirectTo: 'comp1', pathMatch: 'full' },
];
Enter fullscreen mode Exit fullscreen mode

This is the simple code that will help us to have our working router guard. We are converting the subject we had for handling the confirm modal user interactions to the observable which is what this guard expects as the return. Here I haven't added any business logic which can be based upon the variables of the component. Now when you click on Comp2, you will be asked for the confirmation and if you click on OK, you will be navigated away and on Cancel, you will remain on the same view. Here the observable which is returned by canDeactivate will only take the first value it gets.

Hope this small example helped you in understanding something new about canDeactivate, what is it used, and how to use it in Angular.
If you liked it please share it with your friends or if any suggestions reach me out on Twitter or comment below.
Till next time Happy Learning!

Discussion (0)