Reason
In our regular feedback sessions an issue that frequently came up was that out users start introducing data in a form and then press a wrong button and the application navigates to another page. When they come back the form is empty and all of their work is gone.
The application works just fine from a technical point of view, but the user experience suffers.
What can we do?
If the user made any changes to the page and wants to perform a navigation he will get an alert message. If he agrees, the the navigation is done and data is destroyed. If he doesn't, then he will have a chance to save the data and then continue his work.
Angular technical solution
1. First of all we define an interface named ComponentCanDeactivate
export interface ComponentCanDeactivate {
canDeactivate(): boolean;
}
2. And then we implement the interface
export class MyComponent implements ComponentCanDeactivate {
//...
canDeactivate(): boolean {
return !shouldComponentDeactivate;
}
//...
}
3. Create an Angular guard
Use Angular canDeactivateGuard. Where MessageService generates a message based on your needs and context.
I used here the javascript confirm api, but you can use any kind of component/service.
export const formCanDeactivateGuard: CanDeactivateFn<ComponentCanDeactivate> = (
component
) => {
const deactivateMessage = inject(MessageService).getDeactivateMessage;
if (!component.canDeactivate()) {
return confirm(deactivateMessage);
}
return true;
};
4. Use the guard in router configuration
{
path: 'detail/:uuid',
component: MyComponent,
canDeactivate: [formCanDeactivateGuard],
},
If your guard activates before the application is completely loaded, transform the interface into an abstract class and then add the following method in the class.
@HostListener('window:beforeunload', ['$event'])
unloadNotification($event: any) {
if (!this.canDeactivate()) {
$event.returnValue = false;
}
}
Also you can create a default behaviour, by creating a class that implements this interface and extending that class when you need it.
ex:
export class MyDefaultComponent implements ComponentCanDeactivate {
abstract get form(): AbstractControl;
canDeactivate(): boolean {
return !this.form.dirty;
}
}
Conclusion:
We can use guards to prevent a user from performing a navigation when he has unsaved data.
Top comments (0)