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.

image

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.

image

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.

image

(2) User attempts to close the browser while editing a person which contains unsaved changes.

image

(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.

image

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

image

DirtyFlag directive

image

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.

image

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.

image

Create a directive that warns the user to save

We are interacting with the UI, so this means we need another directive.

The view

image

Confirm On Close Directive

This directive uses the modal dialog from AngularUI.

image

Related code:

personManger Service

Method which returns whether or not there are any unsaved changes.

image

And with that your application should present the expected warning dialogs when attempting to close without saving changes.