Conditional validation - making validation more developer friendly
Wednesday, May 5, 2010 at 11:21AM Validation in XPages is sometimes extremely confusing to work with. Especially when you have partial updates on the page.
If you want to trigger a partial update on a page with validation, you need to either set the event that updates the page to Set partial execution mode (ignores validation), or Do not validate or update data (ignore validation/don't calculate fields).
While looking for a way to make it easier to work with partial updates on a page with validation, I stumbled onto this blogpost (JSF). It describes calculating the required property to determine when the validation should execute.
While we can't apply the technique discussed in the above blogpost, we have another tool at our hands, $$xspsubmitid. This field contains the id of the event handler that triggered the update.
I've written a function that lets you test if a specific component triggered an update.
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 < childNodes.length; i++ ){
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 */}
}
Add this function to a SSJS script library.
If you only want the validation to run when the user clicks a specific button, write this in the required-attributes: return submittedBy( 'id-of-save-button' )
For the other kinds of validators, you should be able to use an if-statement to conditionally execute the validator. I took a look at the generated java code for the validators, and from what I can tell, you can put JavaScript statements inside all of them.
E.g.
For constraint validators: if( submittedBy( 'id-of-save-button' ) ){ return /\d+/; }
For big expression statements, it's probably better to do something like this at the top of the script:
if( !submittedBy( 'id-of-save-button' ) ){ return true; }
id-of-save-button is the id/name of the component that triggers a save.
The above code examples makes only triggers validation when a component with id id-of-save-button triggers an update.
If you want multiple actions to trigger the validation, you can do something like this:
if( submittedBy( 'id-of-save-button' ) || submittedBy( 'id-of-save-and-close-button' ) ){..}
When I initially wrote about this technique in my blog, I said that it was a downside that you had to add code to the validators to make them execute conditionally. Since then, I've started using this technique in all my production code. Both my colleagues and me agree that forms in XPages are a lot more predictable when using conditional validation. Less time debugging equals more RAD. :)
Share and enjoy!
validation in
Tips and Tricks 