Implementing a Save Warning in an Angular SPA
I have an Single Page Application written in AngularJS and need to provide a warning to the user if he or she attempts to close a window without saving. Since Angular automatically updates the DOM with a dirty flag this should not be a difficult feature to implement. However, it becomes more difficult when the user is able to open multiple tabs, edit different items, and still receive a warning even if the unsaved changes are in a tab not currently open.
The sample application
The user can select or search for a name and the grid is replaced by an edit view.
The application after opening multiple tabs
The user can continue to open additional persons and a link is created in the left-nav for that person so that the user can navigate between people. Modifications are only saved in the local Angular model and not committed to the server until the user clicks Save for a particular person.
Each name in the left-nav is a link to another person that is in the process of being editing and may or may not have been saved.
Expected behavior if the user clicks the close button or attempts to close the browser window
(1) User clicks the Close button while editing a person which contains unsaved changes.
(2) User attempts to close the browser while editing a person which contains unsaved changes.
(3) User attempts to close the browser while editing a person which contains NO unsaved changes, but there are unsaved changes on a different tab that is not open.
Save and restore the dirty flag from and to the DOM
Since we need to read and write a value in the DOM, this means we need to use a directive. I'm using TypeScript, so you might have to squint a bit to see the underlying JavaScript.
The view
DirtyFlag directive
The important lines of code:
26-30: When the user navigates away from this view, check the value of the $dirty flag on this form. If it is dirty (indicating unsaved changes), then store the id of the current person as dirty using a service named personManger.
23-24: When the directive is first invoked, check if the stored dirty value is true and if so set the $dirty flag on the form.
Related code:
personManger Service
Method to save the dirty flag in the model.
personCtl Controller
When the user saves a person, make sure to reset the dirty value saved in the model as well as the $dirty flag on the form.
Create a directive that warns the user to save
We are interacting with the UI, so this means we need another directive.
The view
Confirm On Close Directive
This directive uses the modal dialog from AngularUI.
Related code:
personManger Service
Method which returns whether or not there are any unsaved changes.
And with that your application should present the expected warning dialogs when attempting to close without saving changes.