About Me

Lotus Notes die hard fan.

Saturday, October 30, 2010

XPages Field Validation and partial refresh


It is a known fact that implementing field validation in XPages is a troublesome activity. Recently I encountered many of these problems. This article is regarding one of the most common problems you would face while implementing field validation.

Consider that you have a requirement to create an XPage for Product order Information with two tables: each table has some mandatory fields.

In the example database the first table has Product Code, Order Number, Customer Name and Order Date fields. And the second table has Ship Date, Quantity, Cost per piece, Tax and Total Cost.

Save button at the top when clicked submits the page to server and invokes the field validation for all the fields. There are two Error Messages controls that are visible on the page after page submit.


These two error messages controls are created for demonstration of partial refresh with field validation. On click of save button since entire page is submitted to the server all the mandatory fields with listed in the error messages which should be fine.

Reopen the Page so that these error messages are gone, Three buttons at the bottom invoke a partial refresh on the bottom table. First button does not have either Set partial execution or Do not validate or update data checked. Ideally the understanding would be that when this button is clicked the only this panel would be sent to the server, validated and Updated.

Click on this button the data on this panel is refreshed, hence only one Error Messages control is visible.

If you pay close attention to what the error messages says:

· Ship Date is Required

· Customer Name is required

· Order Date is required

· Cost is required

· Tax is required

The customer name & order date are outside the bottom table/panel and hence should not be sent to server on this partial refresh but they are listed on this error messages. Unfortunately the above stated popular understanding is wrong. In XPages when a partial refresh is executed on a panel, the complete page is submitted to the server and only the panel on which partial refresh is executed is refreshed on the page. Hence, creates an illusion that only the panel is sent and updated. To confirm I created two random numbers on the page one at the top and another on the panel that is refreshed partially. On click on any of the three buttons at the bottom the computed text field with a random number is refreshed and the field at the top is only refreshed on click of save button (since the entire page is updated).

This is a simple demonstration but consider a scenario where you try to create a dynamic table something like a gridview control from ASP.NET which has three buttons Add Row, Update Row and Delete Row. Ideally on click of Add row button you would want to check if the existing rows In the table have passed validation or not. In that case partial refresh without either Set partial execution or Do not validate or update data checked.

As expected Add row button would validate the panel and show error messages on each click event. If the data in the table is completely validated then it should create a new row. But it does not - if any of the fields outside the refreshing panel is empty or invalid. As proved above only the panel is refreshed but the whole page is sent to the server and validated (must be a bug – this is not AJAX just an illusion).

Right then we can’t change how partial refresh are executed in XPages. All we can do is to learn how to live with them. I created another page to solve this problem.

Solution for partial refresh with validations

Click on the “Validation with Partial Refresh - Solution” link on the example database which solves this problem. I used the following code available on XPagesblog :

function submittedBy( componentId ){
try {
var component = getComponent( componentId );

if( !component ){
throw new java.lang.Exception( 'Component with id "' + componentId + '" not found' );
}

// Cache the id of the event handler
var eventHandlerId = viewScope.get( 'ev-' + getClientId( componentId ) );

if( !eventHandlerId ){
// Find the component's event handler
var eventHandler, childNodes = component.getChildren();

for( var i = 0; i < class="apple-converted-space">
if( typeof childNodes[i] === 'com.ibm.xsp.component.xp.XspEventHandler' ){
eventHandler = childNodes[i];
break;
}
}
eventHandlerId = eventHandler.getClientId( facesContext );
viewScope.put( 'ev-' + getClientId( componentId ), eventHandlerId );
}

// Compare eventHandlerId with $$xspsubmitid
var submitId = param.$$xspsubmitid;

return ( eventHandlerId === submitId );
} catch(e){ /* your exception handling */}
}

And on all the fields outside the refresh panel I used the following formula to calculate the required property submittedBy('saveButton') ;

“saveButton” is the id of save button, I want to validate these fields only when save button is clicked and not on any other event.

Open the page in browser and click “Refresh with Partial refresh” and observe the error messages control that would be visible:

Only the fields in the panel throw an error exception:

· Ship Date is Required

· Cost is required

Tax is required


Just a workaround - I haven't checked if this has been fixed in 8.5.2; Probably would do some RND and confirm the same in the next post.

Example database uses the IBM's 8.5.1 discussion demonstration database template. You can download the same here:

No comments:

Post a Comment