Reference: Warning on Unsaved Changes Functional UI Pattern

This topic contains the following sections:

Overview

One advantage of a rich client web application is the user can easily navigate about anywhere based on current needs. However, with the added flexibility also comes the increased risk of inadvertent unsaved data when navigating from a page. Many applications typically warn the user when this is about to occur. ADF applications can easily implement this type of functionality, using the warning on unsaved changes feature.

At this point, it must be noted that the implementation of this warning targets page navigation. The implementation technique used here does not address navigating between regions of the same page.

The User Experience

ADF applications should warn the user if unsaved changes to a page can be inadvertently lost when navigating from a page. When the user is about to abandon data without posting it back to the server, the following browser based warning dialog could be presented.

Illustration of Unsaved Data Warning Dialog

If the user confirms the navigation by clicking the Ok button, the navigation proceeds and the uncommitted data is lost. If the user cancels the navigation by clicking the Cancel button, the user remains on the same page and is given an opportunity to save the uncommitted data. Uncommitted data is defined as any unsaved data from data controls on a page about to be destroyed. Uncommitted data is not data within a bounded task flow that hasn't been committed yet. Within a bounded task flow, it's common to commit many pages of data at once using the same task flow return activity.

The following describes the recommended development approach for implementing the warning on unsaved changes when navigating from a page. Although other development approaches may be possible to achieve the same desired use case behavior, the recommended approach described within this document is considered the most comprehensive and least complex for ADF applications.

General Use Case

There are three general use cases the warning on unsaved changes feature targets:

Detailed Use Cases

The general use cases listed above are further described by the following detailed use cases when navigation is performed using one of the methods identified below:

If the warning on unsaved changes dialog is implemented, navigating from a page containing a region with dirty data will always result in a warning dialog. This is true even if the region shares the transaction or data-control-scope of the parent page. The following page flow diagram of an example application will be used to explain detailed use case behavior.

It has two task flows defined within adfc-config.xml. One is an unbounded task flow containing two pages: jobs and departments. The other is an unbounded task flow that calls a bounded task flow (i.e., update-employee.xml). The calling unbounded task flow has two pages: home and confirmation. Within the bounded task flow, update-employee.xml, there are two pages: employee and job-history. There are also two task flow returns called from job-history: save and cancel. When the bounded task flow returns to the unbounded task flow, a control flow navigation continues to the confirmation page. Both the departments page within the unbounded task flow and the job-history page within the bounded task flow have an <af:region> tag.

Illustration of Page Flow Diagram of Example Application

Control Flow Navigation Use Cases

The following use cases describe the expected behavior when abandoning unsaved data using control flow rules navigation. ADF Controller will only consider the first control flow rule to be performed in determining if navigation from the page is occurring. No other control flow rules will be evaluated and no activities will be executed. If the user confirms the warning on unsaved changes dialog, a new request will be sent to the server performing the originally requested control flow navigation with its original from-action and from-outcome. Note: Since the page render will actually occur on a different request for the original navigation, any request scope attributes set up during the original postback will not be available.

Control Flow Navigation Use Case ADF Controller Transaction Data Control Scope Description
Within Unbounded Task Flow N/A N/A Yes. Warning on unsaved changes dialog should be presented.

ADF Controller does not manage or specify any transaction or data-control-scope for unbounded task flows. Without knowing further information about the application, abandoned data is determined at the individual page level.

In the application described above, a warning on unsaved changes dialog should appear when using control flow navigation within the unbounded task flow from departments to jobs.
From Unbounded Into Bounded Task Flow N/A -> none any Yes. Warning on unsaved changes dialog should be presented.

In this case, the bounded task flow entered doesn't provide a transaction. Also, ADF Controller does not manage or specify any transaction or data-control-scope for unbounded task flows. So, there's no understanding of how uncommitted data should be handled. Without knowing further information about the application, abandoned data is determined at the individual page level.

In the application described above, a warning on unsaved changes dialog should appear when using control flow navigation from home in the unbounded task flow to employee in the bounded task flow.
From Unbounded Into Bounded Task Flow N/A -> new-transaction

N/A -> requires-transaction

isolated Yes. Warning on unsaved changes dialog should be presented.

The bounded task flow entered begins its own transaction and its data-control-scope is isolated. Therefore, the assumption is the application is designed to commit unbounded task flow data within the unbounded task flow. Once the unbounded task flow is left, there's no guarantee the application will return based on the information available. Without knowing further information about the application, data is considered abandoned.

In the application described above, a warning on unsaved changes dialog should appear when using control flow navigation from home in the unbounded task flow to employee in the bounded task flow.

Note: transaction="requires-existing-transaction" and data-control-scope="isolated" not possible when coming from unbounded task flow.
From Unbounded Into Bounded Task Flow
N/A -> requires-existing-transaction

N/A -> requires-transaction

shared Yes. Warning on unsaved changes dialog should be presented.

The bounded task flow entered joins a non-ADF Controller managed transaction originated within the unbounded task flow. Its data-control-scope is shared. Therefore, one could assume the application is designed to commit or rollback the bounded task flow data within the unbounded task flow and no data would be lost. However, once the unbounded task flow is left, there's no guarantee the application will return based on the information available. Without knowing further information about the application, data is considered abandoned.

In the application described above, a warning on unsaved changes dialog should appear when using control flow navigation from home in the unbounded task flow to employee in the bounded task flow.

Note: transaction="new-transaction" and data-control-scope="shared" not possible when coming from unbounded task flow.
Within Bounded Task Flow none any Yes. Warning on unsaved changes dialog should be presented.

The bounded task flow entered does not define an ADF Controller managed transaction. Its data control frame is dirty, but isn't being destroyed as a result of the navigation. Still, it's not clear how the application is designed to commit or rollback data. Without knowing further information about the application, abandoned data is determined at the individual page level.

In the application described above, a warning on unsaved changes dialog should appear when using control flow navigation within the bounded task flow from employee to job-history.
Within Bounded Task Flow requires-existing-transaction

new-transaction

requires-transaction

any No. Warning on unsaved changes dialog should not be presented.

When navigating within a bounded task flow supporting an ADF Controller managed transaction, it can be assumed any uncommitted data exists by design and will be committed later when the bounded task flow transaction is resolved. Therefore, it can be assumed no data will be lost.

In the application described above, a warning on unsaved changes dialog should not appear when using control flow navigation within the bounded task flow from employee to job-history.
From Bounded to Unbounded Task Flow none -> N/A any Yes. Warning on unsaved changes dialog should be presented.

The bounded task flow exiting does not define an ADF Controller managed transaction. Its data control frame is dirty and is being destroyed as a result of the navigation. It's not clear how the application is designed to commit or rollback data. Without knowing further information about the application, abandoned data is determined at the individual page level.

In the application described above, a warning on unsaved changes dialog should appear when using control flow navigation within the bounded task flow from job-history to the cancel task flow return activity.
From Bounded to Unbounded Task Flow requires-existing-transaction -> N/A

new-transaction -> N/A

requires-transaction -> N/A

any No. Warning on unsaved changes dialog should not be presented.

When navigating out of a bounded task flow supporting an ADF Controller managed transaction, it can be assumed any uncommitted data exists by design and will be committed when the bounded task flow transaction is resolved. Therefore, it can be assumed no data will be lost.

In the application described above, a warning on unsaved changes dialog should not appear when using control flow navigation within the bounded task flow from job-history to the save task flow return activity.
From Bounded to Bounded Task Flow transaction not shared any Yes. Warning on unsaved changes dialog should be presented.

When navigating from one bounded task flow to another not sharing the same ADF Controller managed transaction, once the bounded task flow is left, there's no guarantee the application will return based on the information available. Without knowing further information about the application, data is considered abandoned.
From Bounded to Bounded Task Flow transaction shared any No. Warning on unsaved changes dialog should not be presented.

When navigating from one bounded task flow to another sharing the same ADF Controller managed transaction, it can be assumed any uncommitted data exists by design and will be committed later when the transaction is resolved. Therefore, it can be assumed no data will be lost.

Browser Back Button Navigation Use Cases

Using the browser back button to perform navigation should raise an warning on unsaved changes dialog when uncommitted data is present -- similar to the same corresponding control flow navigation use cases.

Go Link Navigation Use Cases

Using a goLink to perform navigation should raise an warning on unsaved changes dialog if uncommitted data is present, even if the goLink navigates within the same task flow. Since the destination is unknown, any goLink navigation can cause potential data loss. It will always be assumed the goLink navigates outside the current task flow.

URL View Activity Navigation Use Cases

A task flow URL view activity navigates the root page by performing a redirect to any URL. Anytime a URL view activity is executed, the warning on unsaved changes dialog should be raised if uncommitted data is present.

Note: Application developers must set partialSubmit="true" on any actions initiating URL view activities for the warning on unsaved changes to be presented.

Parent Action Activity Navigation Use Cases

Task Flow parent action activities allow regions to queue an ActionEvent to initiate navigation within their parent view port. Parent action navigation is modeled within the application's task flow definition. Therefore, warning on unsaved changes dialog behavior would follow the same rules as the corresponding control flow navigation for bounded and unbounded task flows.

Development Constructs Required

When incorporating the ability to raise a warning on unsaved changes dialog into 11g ADF applications, at least one of the following development constructs should be used to implement the desired use case behavior:

Interaction Behavior

User Enters Data on Page and Leaves Without Submitting Back to Server

  1. User navigates to page.
  2. If the page sets <AF:document uncommittedDataWarning="on"> the view calls trackDirtyStateForRequest() on its DirtyPageHandler with a non-null DirtyPageContext at the beginning of the request. Dirty data will now be tracked.
  3. User updates data on page input component.
  4. View tracks dirty input component.
  5. User attempts to navigate away from page to an external URL before posting updated data back to server.
  6. Because dirty data is being tracked, onBeforeUnload handler was registered with page and onBeforeUnload detects user is attempting to navigate away from the page.
  7. onBeforeUnload handler is performed and the page component tree is walked.
  8. If any dirty components are found within the page component tree, the warning on unsaved changes dialog will be displayed to the user.
  9. If the user confirms the warning dialog, the navigation proceeds, otherwise the user remains on the same page.

User Leaves Page with Uncommitted Data on Server

  1. User updates data on input component of first page within bounded task flow.
  2. User navigates to second page of bounded task flow.
  3. If the second page sets <AF:document uncommittedDataWarning="on"> the view calls trackDirtyStateForRequest() on its DirtyPageHandler with a non-null DirtyPageContext at the beginning of the request. Dirty data will now be tracked.
  4. ADF Controller identifies page and it cares about uncommitted data from the results of the call to DirtyPageHandler.trackDirtyStateForRequest().
  5. Because dirty data is being tracked, ADF Controller tells view if data control frame currently contains uncommitted data.
  6. User attempts to navigate away from second page of bounded task flow to an external URL before posting uncommitted data back to server.
  7. onBeforeUnload handler registered with second page detects user is attempting to navigate away from the page. onBeforeUnload handler was registered with second page because dirty data is being tracked.
  8. onBeforeUnload handler is performed, but none of the page's input components are dirty.
  9. View calls DirtyPageHandler.isDataDirty() to ask ADF Controller if there have been any updates to the data control frame since second page was rendered. ADF Controller considers dirty state of the current view port, as well as its children (regions). If any of them have dirty data, ADF Controller returns true.
    • This step is only performed if data control frame wasn't dirty when page initially rendered.
  10. If ADF Controller identifies any uncommitted data, the warning on unsaved changes dialog will be displayed to the user.
  11. If the user confirms the warning dialog, the navigation will proceed, otherwise the user remains on the same page.

User Performs Control Flow Navigation with Uncommitted Data on Server

  1. User navigates to page within bounded task flow.
  2. If the page sets <AF:document uncommittedDataWarning="on"> the view calls trackDirtyStateForRequest() on its DirtyPageHandler with a non-null DirtyPageContext at the beginning of the request. Dirty data will now be tracked.
  3. ADF Controller identifies page and it cares about uncommitted data from the results of the call to DirtyPageHandler.trackDirtyStateForRequest().
  4. If dirty data is being tracked, ADF Controller tells view if data control frame currently contains uncommitted data.
  5. User attempts to perform control flow navigation either within the page's bounded task flow or its contained regions.
  6. Because dirty data is being tracked, ADF Controller determines whether current page contains uncommitted data. ADF Controller considers dirty state of the current page's bounded task flow, as well as its contained regions. If any of them contain dirty data, ADF Controller returns true.
    • This step is only performed if data control frame wasn't dirty when page initially rendered.
  7. ADF Controller looks for the next target activity based on control flow rules without actually performing navigation.
  8. If target activity is found and isn't the same page, the navigation use case is identified to determine if the warning dialog should be presented when uncommitted data exists.
  9. If it's appropriate to present the warning dialog, ADF Controller skips to the render response lifecycle phase and tells view to display the warning on unsaved changes dialog. ADF Controller informs view using DirtyPageContext.confirmNavigation(), passing the from-action and from-outcome initiating the navigation.
  10. View displays warning on unsaved changes dialog to user.
  11. If user confirms the warning dialog, navigation will proceed. View sends a new request to server performing the originally requested navigation using the from-action and from-outcome initially provided by ADF Controller. Otherwise, user remains on same page.

Pattern Implementation

In order for a page to provide the warning on unsaved changes dialog behavior the following should be implemented:

<AF:document uncommittedDataWarning="on">

The <AF:document> uncommittedDataWarning attribute value should be set on for every page within the application containing an updatable field coming from the data control frame. The updatable field could be included on the page itself or within any of its contained regions. Page fragments appearing within child regions utilize the uncommittedDataWarning setting from their parent page since page fragments don't provide an <AF:document> tag. The default value of the <AF:document> uncommittedDataWarning is off.

Turning on the uncommittedDataChanges setting does make the page slightly heavier, so it should be utilized only where appropriate. When the uncommittedDataChanges behavior is on, client components are created for all page input controls to track their dirty state. When values change from the component's last committed value, the component is considered dirty. Components are considered clean when a PPR request submitting the component's values completes successfully. Setting the uncommittedDataChanges behavior on will also register an onBeforeUnloadListener with the document. When the listener fires, the page component tree is walked. If any dirty components are found, the warning dialog will be displayed to the user.

In the application described above, the home and confirmation page within the application's adfc-config don't contain updatable fields. Therefore, the uncommittedDataWarning value only needs to be set for the jobs and departments pages in the adfc-config and the employee and job-history pages in the update-employee task flow definition. Page fragments used within the regions on the departments and job-history pages utilize the uncommittedDataWarning value from their parent page.

Task Flow Definition <critical>

The task flow definition <critical> property can be set on for at least one task flow existing on the page flow stack at runtime for the warning on unsaved changes dialog to be presented. This scenario will only be checked if the page sets the <AF:documentuncommittedDataWarning> attribute on.

<task-flow-definition>

...

<critical/>

...

</task-flow-definition>

Task flow definitions can only be used to create bounded task flows. Therefore, unbounded task flows cannot specify the <critical> property.

Illustatration of Task Flow Overview Editor with Defintion set to <critical>

The task flow definition <critical> property is also responsible for identifying if implicit save points containing the current application state will be created during the following scenarios:

To enable implicit savepoint creation, the application developer must also set the <enable-implicit-savepoints> configuration property in adf-config.xml to true. The default of the configuration property is false.

In the application described above, the task flow definition <critical> property should be set on the update-employee.xml bounded task flow. It should also be set on the task flow definition for the region located on the departments page. The task flow definition for the region located on the job-history page wouldn't need to set the property since the update-employee.xml task flow definition would also be on the page flow stack during runtime. Unbounded task flows don't specify a <critical> property, but the home and confirmation page within the application's adfc-config don't contain updatable fields anyway. However, the jobs page within the application's adfc-config wouldn't be able to initiate the warning on unsaved changes dialog behavior using the task flow definition <critical> property approach. It would need to utilize the <AF:document uncommittedDataWarning> attribute.


Related Topics

Reference: Dynamic Tabs UI Shell Functional UI Pattern