Sunday, October 23, 2011

How To Disable Action Conditionally from Action Listener

There are use cases, when we want to control command component action execution, based on logic from action listener. If some conditions implemented by action listener are met, we would like to prevent action execution. For today post, I will take example of WebCenter 11g PS3/PS4 navigation and explain how to prevent pprnav action, when there are unsaved changes in the system.

Download sample application - EnterprisePortalApp_v10.zip. This sample is typical WebCenter Portal application, it implements WebCenter navigation model. Navigation model item is defined with both - action listener and action properties - WebCenter pprnav action is defined by default:


In order to be able to discover unsaved changes, instead of pointing to WebCenter navigation context, action listener should point to our custom bean - navigationBean. There is custom processAction(...) method defined inside navigationBean:


This method checks current data control frame for any unsaved changes, based on this check navigation is performed or unsaved changes message is shown.

Sample application contains one task flow, where two fragments are defined. First fragment brings list of jobs, and second displays selected job and allows to edit job details:


We will see now, what will happen when there are unsaved changes in the second fragment and user clicks on WebCenter menu. We select job for editing:


Open selected job details, edit data:


Without saving or reverting changes, click on any item from WebCenter menu. Our custom processAction(...) method will be invoked, where current data frame will be checked for unsaved data - unsaved changes message will be shown to the user and further navigation will be prevented. However - we loose editing screen and are navigated back to the first fragment from the task flow:


What is the reason for this? Logically - because WebCenter menu defines pprnav action by default, even we prevent further navigation from custom action listener, action method is still invoked:


There is a way to control action from action listener. If there are unsaved changes, we can get instance of RichCommandLink menu item and set action expression to be Null. Keep in mind, action method is invoked always after action listener method - this would mean that in our case, because we are setting action expression to be Null - action will not be invoked at all, when there are unsaved changes and we will stay on current fragment:


Once action expression is set to be Null, it will remain as Null always for life span of current session. This means for next request we need to reset it to be pprnav again. We can set action expression to be pprnav, if there is unsaved data - it will be tracked during same request and action expression will be set back to Null again:


Focus stays on current fragments, with unsaved data:


5 comments:

Henry said...

Great post, just what I was looking for! Thanks.

Jlopez said...

Great post Andrejus,

I'm trying to use it to change the action from the bean (in case that action has to had not null value). All runs OK except the line:

link:setActionExpression(this.getMethodExpression("pprnav"));

this does reference to processAction class and it has not getMethodExpression.

Then I've had to create a function using inside CreateMethodExpression method.

I would like how to do as you with only one line.

Thank you very much !!

Tarique said...

Thanks Andrejus. Previously I used to do this in a little lengthy way. This is short & smart way.

Andrej Baranovskij said...

I'm glad it was helpful :)

Yo said...

Hi Andrejus,

Do you know any method to cancel navigation when the action is in execution already? I would like to let the model being updated, test some condition, and cancel navigation if it's meet.

Thanks!