Rollback button with the property 'immediate' set to 'true' doesn't rollback values from a task flow.

来源:互联网 发布:淘宝收藏夹批量管理 编辑:程序博客网 时间:2024/05/21 05:18

Applies to:

Oracle JDeveloper - Version: 11.1.1.0.1
This problem can occur on any platform.

Symptoms


Rollback button with the property 'immediate' set to 'true' doesn't rollback values from a task flow. The values outside the region however are reset as expected.

It works fine for all values, inside and outside the taskflow, when the button as the default:
immediate="false"

Cause

The Rollback button has a <af:resetActionListener> that is the reason why the form values
get reset properly but the region's does not, especially when "immediate=true". This is by design.

<af:commandButton actionListener="#{bindings.Commit.execute}"
  text="Commit"/>
<af:commandButton actionListener="#{bindings.Rollback.execute}"
  text="Rollback" 
  immediate="true">
  <af:resetActionListener/>
</af:commandButton>



The <af:resetActionListener> is an ADF Faces tag that by design will walk up the chain to
locate the closest <af:form>/<af:subform>/<af:region> and set that as the root
component whose children need to be reset.

If, for example, the Rollback button is a child of the <af:form>, the form iterates over its children and resets the value for input components, resets the collection component's stamp state (if found),
but for regions it does nothing.
This is by design because "resetting a region" has more complex connotations.
It's not always clear if the user
* wants to reset the contents of the fragment currently displayed
* or if they want to reset all the fragment values (including hidden ones)
* or if you want transaction (of the DataControl frame) associated with the region to be rollbacked.


NB: if you were to remove the <af:resetActionListener> tag (with "immediate=true" ), the
Rollback action does not reset the values of the form or the region.
This is expected based on the description above.

Solution

If you really want to reset the contents of the form and the region and not get validation errors then you have to do the following:

  1. Make the 'Rollback' button to be immediate  
    (normally already done)
  2. Add a <af:resetActionListener/> to reset the form 
  3. Implement a solution to call component.resetValue() on the components inside the region's currently displayed fragment.
  4. Set 'partialSubmit' to true for the button "Rollback" to perform a partial postback instead of a full postback.


JSPX Page

<af:commandButton actionListener="#{bindings.Commit.execute}"
   text="Commit" id="cb1"/>
<af:commandButton actionListener="#{bindings.Rollback.execute}"
   text="Rollback" partialSubmit="true"
   immediate="true" id="cb2">
   <af:resetActionListener/>
      <f:actionListener binding="#{TestBean.rollbackActionListener}"
         type="test.view.RollbackActionListener"/>
</af:commandButton>


TestBean.java

...
public class TestBean
{
private RollbackActionListener actionListenerImpl;

public RollbackActionListener getRollbackActionListener()
{
   return actionListenerImpl;
}

public void setRollbackActionListener(RollbackActionListener actionListenerImpl)
{
   this.actionListenerImpl = actionListenerImpl;
}

 

//Implement your custom RollbackActionListener class to reset the values inside a region.If you want the values of nested regions also to be reset then implement the logic accordingly.


RollbackActionListener.java

package test.view;

import java.util.Iterator;

import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;

import oracle.adf.view.rich.component.fragment.UIXRegion;
import oracle.adf.view.rich.component.rich.fragment.RichRegion;

import org.apache.myfaces.trinidad.component.UIXCollection;
import org.apache.myfaces.trinidad.component.UIXEditableValue;
import org.apache.myfaces.trinidad.context.RequestContext;
import org.apache.myfaces.trinidad.util.ComponentUtils;

public class RollbackActionListener implements ActionListener
{
/**
* Processes the ActionEvent to rollback and queues an ActionEvent on the region to explicitly
* reset the current form in the fragment inside the region.
* @param event
*/
public void processAction(ActionEvent event)
{
   // locate the region
   UIComponent src = event.getComponent();
   UIComponent comp = ComponentUtils.findRelativeComponent(src, "taskf1");

   if (comp instanceof RichRegion)
   {
      RichRegion region = (RichRegion) comp;
      _resetChildren(region);
   }
}

private void _resetChildren(UIComponent component)
{
   Iterator<UIComponent> kids = component.getFacetsAndChildren();

   while (kids.hasNext())
   {
      UIComponent kid = kids.next();

      if (kid instanceof UIXEditableValue)
      {
         ((UIXEditableValue) kid).resetValue();
         RequestContext.getCurrentInstance().addPartialTarget(kid);
      }
      else if (kid instanceof EditableValueHolder)
      {
         _resetEditableValueHolder((EditableValueHolder) kid);
         RequestContext.getCurrentInstance().addPartialTarget(kid);
      }
      else if (kid instanceof UIXCollection)
      {
         ((UIXCollection) kid).resetStampState();
         RequestContext.getCurrentInstance().addPartialTarget(kid);
      }
      else if (kid instanceof UIXRegion)
      {
         // TODO: If you have inner regions then you may need to reset those as well
         continue;
      }

     _resetChildren(kid);
    }
}

private void _resetEditableValueHolder(EditableValueHolder evh)
{
   evh.setValue(null);
   evh.setSubmittedValue(null);
   evh.setLocalValueSet(false);
   evh.setValid(true);
}
}
url:http://blogs.oracle.com/vijaymohan/2010/02/rollback_button_with_the_property_immediate_set_to_true_doesnt_rollback_values_from_a_task_flow.html
原创粉丝点击