Tuesday, September 7, 2010

Deep dive into Visualforce <apex:actionregion /> tag !

<apex:actionRegion /> is interesting and somewhat ignored tag in Visualforce. Tag is ignored, because Visualforce documentation is not in depth, to explain the real utility of this tag. So this post explains some stuff around action region to make it easy for developers to understand.

Special thanks to @RajendraOgra for sharing his findings and information around this tag with me.

What is Region aka ActionRegion ?

The <apex:actionRegion> component specifies the components to be processed on Force.com server. If no <apex:actionRegion> is defined the whole View functions as a region.

Here components means, all visualforce tags like inputField, inputText, outputPanels etc.

And component processing includes, atleast

  • conversion : converting from user inputted strings to date, numbers etc.
  • validation : running validations like checking required fields
  • model update : updating apex bindings i.e. Controller variables binded to visualforce page merge fields.

Note, even when using <apex:actionRegion/>, the whole Form is still submitted but only part taken into region will be processed.

Example:

<apex:form>
      ...
      <apex:actionRegion>
            <apex:commandLink/>
      </apex:actionRegion>
      ...
<apex:form>

Here the complete form is submitted when request is generated by <apex:commandLink/> but only markup between <apex:actionRegion > and </apex:actionRegion> is processed on server.

Example 2: Nesting of ActionRegion(s)

<apex:form>
       ...
      <apex:actionRegion>
            <apex:commandLink value="Link 1" id="link1"/>
            <apex:actionRegion>
                 <apex:commandLink value="Link 2" id="link2"/>
            </apex:actionRegion >
      </apex:actionRegion>
      ...
<apex:form>

The regions could be nested. Server picks out and processes only the region, which contains the component that initiates the request. Here in above example, the external region is processed for link1 and the internal one is processed for link2.

ActionRegion in Action !

Now, we will go thru a simple visualforce code snippet to understand the dramatic effect of <apex:actionRegion /> tag on validations and model update.

Scenario :

  • We are having a simple page, comprising of two input fields i.e. name and job.
  • Name has keypress visualforce actionSupport handler attached to it, it just re-prints/re-renders the typed text in name field over an <apex:outputText />
  • Job input field is a “required” text field on the page.

Sample Code :

Controller

public class regioncontroller {
    public String name { get; set; }
    public String job { get; set; }
}

VF page

<apex:form >
   <apex:pageMessages id="messages1"/>    
   <apex:pageBlockSection columns="2" title="WITHOUT Action Region">
      <apex:outputText value="Name" />
      <apex:inputText value="{!name}">
         <apex:actionSupport event="onkeyup" reRender="outname,messages1" />
      </apex:inputText>
      <apex:outputText value="Job" />
      <apex:inputText required="true" id="job2" value="{!job}" />
   </apex:pageBlockSection>
<apex:outputText id="outname" style="font-weight:bold" value="Typed Name: {!name}" />
</apex:form>

When we run this code sample i.e. type something in name field we get validation error as follows

Whats this Issue !

Type the name. The outputText “outname” component should reappear after you. However, in the first case, this activity will be aborted because of the other field with required="true". You will see only the error message while the "Job" field is empty. After filling in something in Job field, you can see outputText getting updated on keypress in Name field.

How to fix this ?

To fix this, we need to use actionRegion, as of now all the visualforce components in the page are getting processed when request is generated on keypress.  So a validation error does not allow to process an ajax input(i.e. name’s keypress).  If we simply demarcate the inputText “Name” with “ActionRegion” the problem will be solved, because then only this component will be processed by the force.com server. Here is the fixed code snippet and it works well, without even filling in any job details.

<apex:form >
   <apex:pageMessages id="messages1"/>    
   <apex:pageBlockSection columns="2" title="WITH Action Region">
      <apex:outputText value="Name" />
      <apex:actionRegion >
         <apex:inputText value="{!name}">
            <apex:actionSupport event="onkeyup" reRender="outname,messages1" />
         </apex:inputText>
      </apex:actionRegion>
      <apex:outputText value="Job" />
      <apex:inputText required="true" id="job2"  value="{!job}" />
   </apex:pageBlockSection>
   <apex:outputText id="outname" style="font-weight:bold" value="Typed Name: {!name}" />
</apex:form>    

Note we just added <apex:actionRegion /> around input text, thats it.

Live Demo

Want to play and see this actionRegion’s stuff in action, here is the link to my public site vf page. You can play with both cases i.e. with / without action region on the same page.

Complete Source of the Demo VF Page

I started using http://snipplr.com/, great website for quickly sharing code snippets. Here are the links to the source code.

Other References

Visualforce internally runs on top of JSF and Rich Faces frameworks of J2EE. So many of the visualforce tags are port of rich faces JSF tags. I got this understanding around actionRegion from Rich Faces documentation. The above demo code is port of Rich Faces “region” sample itself. So if you are still hungry to learn more, please refer rich faces docs, here are the rich faces links

Other Notes

I am researching on other interesting attribute available on <apex:actionRegion /> i.e. “renderRegionOnly”. To avoid having too much information in this blog post about action-region, I will come up with more details on this in another post.