Alfresco: Disable the next button in an advanced workflow according to a constraint
Normally the Alfresco constraints doesn't work in an advanced workflow. This issue is stated here:https://issues.alfresco.com/jira/browse/ALF-1846
According to Alfresco it's fixed in 3.4.2. But I have a work-around/fix for all the older implementations if it's limited to 1 transition button.
We have a task model type:
<type name="test:submitTask">
<title>Submit Task</title>
<parent>bpm:workflowTask</parent>
<properties>
<property name="test:constraintField">
<type>d:text</type>
<mandatory>true</mandatory>
<constraints>
<constraint ref="test:minCharConstraint" />
</constraints>
</property>
</properties>
</type>
<constraint name="test:minCharConstraint" type="LENGTH">
<parameter name="minLength">
<value>3</value>
</parameter>
<parameter name="maxLength">
<value>255</value>
</parameter>
</constraint>
We have a workflow transition:
<transition name="Next" to="Next Info">
<action class="org.alfresco.repo.workflow.jbpm.AlfrescoJavaScript">
<script>
//Do Something or Don't :)
</script>
</action>
</transition>
We have a webclient-config-custom:
<config evaluator="node-type" condition="test:submitTask">
<property-sheet>
<show-property name="test:constraintField"/>
</property-sheet>
</config>
This is very basic when you model with advanced workflow. So now we need to be able to constrain this "test:constraintField" so that the minimum characters should be 3.
Now if we test this, the check will be done on save changes, but not on the "Next" transition button.
To get this to work, we need to create a component generator and make some few adjustments.
Because it's a text field, we just need to extend the TextFieldGenerator.
I've made the generator globally as you can see below:
public class MinCharGenerator extends TextFieldGenerator {
private String nextTransition;
private final String PREFIX_TRANSITION = "transition_";
@Override
@SuppressWarnings("unchecked")
protected void setupConstraints(FacesContext context, UIPropertySheet propertySheet, PropertySheetItem property,
PropertyDefinition propertyDef, UIComponent component) {
if (nextTransition != null && nextTransition.length() > 0)
propertySheet.setNextButtonId(PREFIX_TRANSITION + nextTransition);
if (propertySheet.inEditMode() && propertySheet.isValidationEnabled() && propertyDef != null) {
List<ConstraintDefinition> constraints = propertyDef.getConstraints();
for (ConstraintDefinition constraintDef : constraints) {
Constraint constraint = constraintDef.getConstraint();
if (constraint instanceof RegexConstraint) {
setupRegexConstraint(context, propertySheet, property, component, (RegexConstraint) constraint, true);
} else if (constraint instanceof StringLengthConstraint) {
setupStringLengthConstraint(context, propertySheet, property, component, (StringLengthConstraint) constraint, true);
} else if (constraint instanceof NumericRangeConstraint) {
setupNumericRangeConstraint(context, propertySheet, property, component, (NumericRangeConstraint) constraint, true);
}
}
}
}
public String getNextTransition() {
return nextTransition;
}
public void setNextTransition(String nextTransition) {
this.nextTransition = nextTransition;
}
Let's look at the method setupStringLengthConstraint(..).
The important part of this, is just setting the boolean from false to true. The method is described in the JavaDoc:
/**
* Sets up a default validation rule for the string length constraint
*
* @param context FacesContext
* @param propertySheet The property sheet to add the validation rule to
* @param property The property being generated
* @param component The component representing the property
* @param constraint The constraint to setup
* @param realTimeChecking true to make the client validate as the user types
*/
So we just enabled the realTimeChecking, which is set to false by default (I don't know why, but it's lame). I mean the JavaScripts methods are there to validate directly, then why don't use them???
Now if you just deploy this ComponentGenerator and enable it in the webclient-config-custom then you'll see that the saveChanges button is disabled by default and will get enabled after the 3rd character.
But we also want to enable this validation on our Transition button. So i've added a parameter to our Generator to know which is the transition button.
Let's look at the faces-config-custom.xml.
<managed-bean>
<!-- Component which checks if the minimum characters are filled in -->
<managed-bean-name>
MinCharGenerator
</managed-bean-name>
<managed-bean-class>
package.MinCharGenerator
</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>nextTransition</property-name>
<value>Next</value>
</managed-property>
</managed-bean>
The value in here, is the Transition name in the advanced workflow.
if (nextTransition != null && nextTransition.length() > 0)
propertySheet.setNextButtonId(PREFIX_TRANSITION + nextTransition);
The code line above, sets the transition button as a wizard next button. This won't make sense directly, but if you look at the Javascript which is created in the class UIPropertySheet in method renderValidationScript(...).
You'll see that by default is disables the next & finish button. The finish button --> is the "Save Changes" button and there is no next button assigned in an advanced worfklow. The next button is mostly assigned in the default wizards.
Ofcourse you could rewrite the private renderValidationScript method, but then you're rewriting alfresco core code. With this implementation it's just an extension to the default code.
Have fun with it and if you have any questions just contact me through my website MITCO.