Angular: Prevent the user from accidentally losing data while navigating your app.
Remember that time it took quite a bit of time to fill in that form and then lost all that progress by accidentally clicking on a link or navigation item? Remember that frustrating feeling you had there? We would like to protect our users from experiencing that while using our app.
We need to make sure that, when a user wants to navigate away from a page, we check if there are still changes pending to be saved. This can be achieved by leveraging the power of the build-in Angular router guards with our own custom logic.
We will build a solution where the user is notified that there are still some unsaved changes on the page and ask for confirmation to navigate away.
1. Schematic representation
As we can see in the diagram above when the user initiates the navigation we need to check if the component where he navigates away from is protected by a guard, if not we just proceed with the navigation.
When the component is protected by a guard we need to check if the component can be deactivated, if all checks pass we can proceed with the navigation, if a check fails we need to ask the user for confirmation before we proceed with or cancel the navigation.
2. create an interface
We need a way for our guard to ask the component if it can be deactivated, we can achieve this by implementing a function in our component and listen to the returned value of that function in our guard. the cleanest way to do this is by creating an interface.
3. create the guard
We can now create a can-deactivate guard that uses this interface and, since we are only interested in if or not a component can be deactivated, returns an observable<boolean>
This guard doesn't do much yet so let’s proceed with creating a service where we can trigger the confirmation dialog and that can let us know if or not the user has confirmed the navigation
4. create a service
We need 2 states, 1 to tell the application that it should open a dialog and 1 to let our guard know what the decision of the user was, also we need 4 methods to toggle these states
5. Connect our guard with the service
Now we have our service, our way of communicating, we can start connecting the dots.
First, we update our guard
Second, we update our route with our guard.
Next, we also need to update our component, we need to add our canDeactivate function to the component. to avoid mistakes and errors we can do this by implementing our interface.
Last, we need to create our dialog, I didn't include the code for the dialog component, this would take us too far from the purpose of this post.
We can now prevent our users from losing data while navigating our app thus saving tons of frustration. Thanks to the easily used interface we only need to add the guard to the route and implement our interface in every component we want to protect, also we left the discussion if or not to deactivate completely within the component self, giving us the opportunity to write custom rules per component.
Thanks for reading!