Displaying PrimeNG confirmation dialog with guarded routes
In Angular 2+, you can protect routes with guards. The most likely used guard types are CanActivate
and CanDeactivate
. The first guard type decides if a route can be activated, and the second one decides if a route can be deactivated. In this blog post, we will discuss CanDeactivate
. This is an interface having only one method canDeactivate
.
This method can return Observable<boolean>
, Promise<boolean>
or boolean
. If the value of boolean is true
, the user can navigate away from the route. If the value of boolean is false
, the user will stay on the same view. If you want to protect your route from navigating away under some circumstances, you have to do three steps:
- Create a class that implements the interface
CanDeactivate
. The class acts as a guard which will be checked by the router when navigating away from the current view. As you can see, the interface expects a generic component class. This is the current component rendered within the<router-outlet>
tag. - Register this guard as provider in a module annotated with
@NgModule
. - Add this guard to the route configuration. A route configuration has the property
canDeactivate
where such guards can be added multiple times.
You might want to check out an example from the official Angular documentation. In this blog post, we would like to implement a typical use case where we will check if there are some unsaved input changes made by user. If the current view has unsaved input values and the user tries to navigate away to another view, a confirmation dialog should be shown. We will use ConfirmDialog from the PrimeNG UI library for Angular 2+.
Now, hitting the Yes button leads to navigating to another view.
Hitting the No button, prevent the the process of navigating from the current route. Let’s create the first view with an input element, a submit button and PrimeNG component <p-confirmDialog>
.
The corresponding component for this template keeps the dirty
state of the form which indicates that the form is being edited.
We will not implement any sophisticated algorithms in order to check if the input value was really changed. We just check the form’s dirty
state. If the form is not being edited, the navigation on submit should be fine. No need to ask the user about unsaved changes. Now, we have to inject the PrimeNG ConfirmationService
into our guard implementation, which is required to display a confirmation dialog, and use it like this within the canDeactivate
method:
But there is a problem. The confirm
method doesn’t return required Observable<boolean>
, Promise<boolean>
or boolean
. The solution is to create and return an Observable
object by invoking Observable.create()
. The create
method expects a callback with one parameter: observer: Observer<boolean>
. Now we need to do two steps:
- Put the call
this.confirmationService.confirm()
into the callback’s body. - Pass
true
orfalse
to the subscriber by invokingobserver.next(true)
andobserver.next(false)
respectively. The subscriber is the PrimeNG’s componentConfirmDialog
which needs to be informed about user’s choice.
The full implementation of the UnsavedChangesGuard
is shown below.
If you prefer Promise
instead of Observable
, you can return Promise
as follows:
The complete project is available on GitHub: https://github.com/ova2/frontend-tooling-tutorial/tree/master/angular-playground/router-primeng-confirmdialog