Rules are probably best described by using examples. This chapter contains numerous real world samples.
...
Step 1 is named Expense Report, Step 2 is named Manager Approval and step 3 is named Accounting in the flow designer to match the sections in the parent form. The Manager role has been assigned to step 2 and the Accounting role has been assigned to step 3.
Here is an example of a rule that shows the Expense report details when the form loads, (the Manager Approval and Accounting sections are hidden) on step1, makes the Manager Approval section visible in the second step of the flow when performed by a manager and shows the Manager Approval and Accounting sections on step 3 when it is performed by an accounting department employee.
Code Block | ||
---|---|---|
| ||
if (form.load) { var an = _data.getParameter("flow.activity.name"); if (an === 'Manager Approval') { ManagerApproval.visible = true; } if (an === 'Accounting') { ManagerApproval.visible = true; Accounting.visible = true; } } |
Show/Hide Manager Approval on Step 2 and 3 of a flow
You have a flow and the first form has a Section for manager approval. The Section is hidden by default. Here is an example of a rule that makes the section visible in the second and third steps of the flow which are linked steps assigned to the manager and VP roles.
Code Block |
---|
if (form.load) { var an = _data.getParameter ("flow.activity.name"); if (an === 'Manager' || an === 'VP'){ ManagerApproval.visible = true; } else { ManagerApproval.visible = false; } } |
...
You can build forms/flows In that meet Section 508 and WCAG 2.0 accessibility standards. Accessible forms/flows can assist users with visual and motor impairments. When the Accessible property is enabled for a form/flow, the error, "You can't leave this empty <control name>" displays, if users move ahead from a required field without filling it. The status property for the empty control becomes invalid and sets the error message. Normally, the status property can be used in a business rule. For example, let's say a form has a text control named 't', and a message control named "m". If you write a rule to update the message field (control named m) with the STATUS of the required/invalid control (control named t), as shown below, it will not work because the "You can't leave this empty" message for a required control is not treated as it's status.
Code Block | ||
---|---|---|
| ||
if(!t.valid) { m.value = t.status; } |
...
Code Block |
---|
var x; var selectedcolors = ''; for (var i = 0; i < RGB.value.length; i++) { var v = RGB[i].value; for (x in RGB.options) { var opt = RGB.options[x]; var val= opt.split('=')[0]; var lab= opt.split('=')[1]; if (v === val) { selectedcolors = selectedcolors + ' ' + lab; } } } SelectedColors.value = selectedcolors; |
Retrieving or Setting the Comment Property for Selection Controls
...
Business rules can be written to retrieve/set the value of the Comment field using the commentValue property. Note that the initial value of the commentValue is null. Your rules may have to be coded to check for that.
This simple rule copies the value in the comment field of a dropdown control named Supervisor to a text field named. The rule will run only if the value in the comment field is not null.
Code Block |
---|
if(Supervisor.commentValue != null){
OtherSupervisor.value =Supervisor.commentValue;
} else {
OtherSupervisor.value = "";
} |
Review this special syntax to reference comment fields in templates.
T/F Boolean
T/F controls are simplified checkbox controls with only a single visible option. This rule makes the control named "s" visible if the T/F control named "agree" is checked and invisible if the T/F control named "agree" is unchecked.
Code Block |
---|
if (agree[0].value === 'true') {
s.visible = true;
} else {
s.visible = false;
} |
To set the checkmark on a T/F control:
Code Block |
---|
// check the TF control
agree.value = 'true';
|
To clear a checkmark from a T/F control you must set the value to null and ensure that the control is not required.
Code Block |
---|
agree.required = false;
agree.value = null; |
Repeating Checkboxes
Checkboxes inside repeat controls must be treated as an array (each checkbox control's values) of checkbox option values which is inside another array (the repeating checkbox control itself). This form example has a repeating section containing two controls -- Message which is a text control and AreYouAttending which is a checkbox control with a single option 'yes'. To access the selected options the syntax is:
AreYouAttending[i].value[0] === 'yes'
...
Repeating Checkboxes
Checkboxes inside repeat controls must be treated as an array (each checkbox control's values) of checkbox option values which is inside another array (the repeating checkbox control itself). This form example has a repeating section containing two controls -- Message which is a text control and AreYouAttending which is a checkbox control with a single option 'yes'. To access the selected options the syntax is:
AreYouAttending[i].value[0] === 'yes'
Code Block | ||
---|---|---|
| ||
for (var i = 0; i < AreYouAttending.value.length; i++)
{
if (AreYouAttending[i].value[0] === 'yes') {
Message[i].value = Name.value +
' is attending event #' + i;
}
} |
Retrieving or Setting the Comment Property for Selection Controls
Dropdowns, Checkboxes and Radio controls have the capability to display a Comment field if the user selects the last option. It is most often used as an Other - please specify" option. In the Forms designer, check the Comment checkbox in the Properties panel and provide a # of rows for the comment area. If the user selects this option, a comment box will appear below asking the user to provide details.
Business rules can be written to retrieve/set the value of the Comment field using the commentValue property. Note that the initial value of the commentValue is null. Your rules may have to be coded to check for that.
This simple rule copies the value in the comment field of a dropdown control named Supervisor to a text field named. The rule will run only if the value in the comment field is not null.
Code Block |
---|
if(Supervisor.commentValue != null){
OtherSupervisor.value =Supervisor.commentValue;
} else {
OtherSupervisor.value = "";
} |
Review this special syntax to reference comment fields in templates.
Dynamic Options
Selection controls' (radios, checkboxes, dropdowns, T/F) options can be set dynamically via rules rather than statically via the control's options property. However if the control comes from an XSD schema data source rather than one of the standard palette controls, then the designer must take care to not set the options to something outside of what is valid for that schema element. For example if your XSD has a string enumeration and list valid options as 'red', 'green', and 'blue', then you should not use a rule to dynamically set the options to 'small', 'medium', 'large'. If you do then then your form will not work correctly in use mode. If a user selects the option 'small' they will get a validation error on the form. This is because 'small' is not one of the options allowed by your underlying XSD schema.
Tip |
---|
If you are setting the options of a Checkbox control with a business rule, make sure the control has a minimum of two options defined in the designer if you are planning to give your users the ability to Save the form/flow to the Task List. If the Checkbox only has one option defined in design mode, then the options selected by the user before they click the Save button will not display when the Saved task is retrieved from the Task List. |
T/F Boolean
T/F controls are simplified checkbox controls with only a single visible option. This rule makes the control named "s" visible if the T/F control named "agree" is checked and invisible if the T/F control named "agree" is unchecked.
Code Block |
---|
if (agree[0].value === 'true') {
s.visible = true;
} else {
s.visible = false;
} |
To set the checkmark on a T/F control:
Code Block |
---|
// check the TF control
agree.value = 'true';
|
To clear a checkmark from a T/F control you must set the value to null and ensure that the control is not required.
Code Block |
---|
agree.required = false;
agree.value = null; |
String Concatenation
Message controls can be used in business rules to create summary information on your form from values entered into earlier form fields. This rule uses javascript variables to concatenate form field values, text strings and html to format a nice summary page:
...
Code Block |
---|
if (searchChoice.value === 'Organizations')
{
orgname.visible = true;
firstname.visible = false;
lastname.visible = false;
clientId.visible = false;
}
else if (searchChoice.value === 'Individuals')
{
orgname.visible = false;
firstname.visible = true;
lastname.visible = true;
clientId.visible = false;
} else if (searchChoice.value === 'Client ID')
{
orgname.visible = false;
firstname.visible = false;
lastname.visible = false;
clientId.visible = true;
} |
Dynamic Options
...
} |
Triggers & Dynamic Options
...
You may want to calculate a date in a workflow based on a five day work week. This is a common business scenario and may be helpful if you are using the Escalations feature. It is not possible to select calendar or working days for the Days interval of the Escalation feature at this time but this enhancement is planned for a future release. As a work-around, you can calculate X number of working days from the current date, and set that date in a Date control on your form. Then while configuring escalations, use the ‘Complete By’ condition and select the Date control.
Here is the business function/rule that will add 3 working days to the current date to give you the escalation date. Copy/paste the entire rule including the function in the Rule Editor. Substitute the name of your date control for <your date control>:
Code Block | ||
---|---|---|
| ||
function calcWorkingDays(fromDate, days) { var count = 0; while (count < days) { fromDate.setDate(fromDate.getDate() + 1); if (fromDate.getDay() !== 0 && fromDate.getDay() !== 6) { // Skip weekends count++; } } return fromDate; } if (form.load && <your date control>.value.length === 0){ var numWorkingDays = 3; var today = frevvo.currentDate().split('-'); var escDate = calcWorkingDays(new Date(today[0], today[1]-1, today[2]), numWorkingDays); var m = escDate.getMonth() + 1; var d = escDate.getDate(); var y = escDate.getFullYear(); <your date control>.value = m + '-' + d + '-' + y; } |
...
Code Block |
---|
var date = datefield.value.split('-'); var dateStr = date[2] + '/' + date[1] + '/' + date[0] ; Msg.value = "I selected the date: " + dateStr; |
Checking a Date for Extra Digits
This rule uses the valid property to verify that the entered date does not contain extra digits. For example, if a user enters a date with a 6 digit year (1/2/201717) into a control named StartDate, the customized error message in the rule displays.
Code Block | ||
---|---|---|
| ||
if (StartDate.value.length > 10) {
StartDate.valid = false;
StartDate.status = 'Invalid. Please check that the date is entered in the mm-dd-yyyy format';
} else {
StartDate.valid = true;
} |
Times
The date control can be set to either just a date, just a time, or a combined date/time. Here are several examples of initializing a time control named Tm;
...
Imagine an airline reservation form where the number of traveler information sections displayed is based on the number of airline tickets purchased. There is a field in the form for the number of tickets named count and a repeat with a section including controls to collect information about each traveler. You can leave the default values for the Min/Max properties of the Section in the Forms designer or set them to any values provided the min value < max value and the max value > min value.
This is an example of a business rule that displays the number of sections based on the number of purchased airline tickets.
Code Block | ||
---|---|---|
| ||
var i; if (TravelRepeat.itemAdded) { i = TravelRepeat.itemIndex; TravelNo[i].value = 1 + i; } else { if (count.value > TravelNo.value.length){ TravelRepeat.maxOccurs = count.value; TravelRepeat.minOccurs = count.value; } else { TravelRepeat.minOccurs = count.value; TravelRepeat.maxOccurs = count.value; } for (i=0; i<TravelNo.value.length;i++) { TravelNo[i].value = 1 + i; } } |
...
- The first part of your rule should retrieve the results set (this part of the rule is not shown here). In this example, the user enters a number in the Number of Travelers field in the form.
- The itemAdded statement is needed to determine if you are adding more sections. The first time the rule runs, this statement will evaluate as false and run the else statement
- Evaluate if the number of sections needed is greater than the number or existing sections. If true, set the maxoccurs first.
- if the number of sections needed is less than the number of existing sections then set the minoccurs first.
- The rule will loop through the existing sections and set the values in the TravelNo field. If there are still additional sections to be added after the rule has looped through the existing sections, the itemAdded lines will run.
Entering "5" as the number of travelers, sets the minOccurs and maxOccurs to 5 and shows 5 information sections.
This rule sets the Min/Max properties to the same values so the
plus and minus icons are not visible. This prevents users from adding repeating items....
Let's take a look at a simple example. Users are instructed to enter a capital Y in a table if they are planning on calling a customer. The user enters the "Y" then tabs to the company name column. The minus icon for that row will disappear.
In this example, the name of the table control is CustomerTable and column 0 in the table is named ContactCustomer.
Here is the rule:
Code Block |
---|
for (var i=0; i<ContactCustomer.value.length; i++) { if (ContactCustomer[i].value === "Y") { CustomerTableItem[i].deletable = false; } else { CustomerTableItem[i].deletable = true; } } |
...
- The first part of your rule should retrieve the results set or as in this example, the user can enter a number in the Number of Travelers field in the form.
- The itemAdded statement is needed to determine if you are adding more rows to the table.The first time the table populates this statement will evaluate as false and run the else statement
- Evaluate if the number of rows needed is greater than the number or existing rows. If true, the table needs to set the maxoccurs first because the table needs to increase.
- if the number of rows needed is less than the number of existing rows (the table needs to shrink) then the table needs to set the minoccurs first.
- The rule will loop through the existing rows and set the values in the appropriate columns. If there are still additional rows to be added to the table, after the rule has looped through the existing rows, the itemAdded lines will run.
- This rule sets the Min/Max properties to the same values so the plus and minus icons are not visible. This prevents users from adding or removing table rows.
Code Block | ||
---|---|---|
| ||
var i; if (TableRepeat.itemAdded) { i = TableRepeat.itemIndex; TravelID[i].value = 1 + i; } else { if (count.value > TravelID.value.length){ Table.maxOccurs = count.value; Table.minOccurs = count.value; } else { Table.minOccurs = count.value; Table.maxOccurs = count.value; } for (i=0; i<TravelID.value.length;i++) { TravelID[i].value = 1 + i; } } |
The images show the table when the user enters 5 as the number of travelers and then changes the value to 3.
Section | ||||
---|---|---|---|---|
|
...
A rule can dynamically display an image uploaded to your form via the upload control. In this example the upload control is named 'u'. The form also must contain a message control as a place holder for displaying the uploaded image. The rule dynamically creates a URL to the uploaded image in the temporary attachment repository. The upload control's value 'u.value' is a GUID that uniquely identifies the attachment. The uploaded image will be included in the submission PDF.
Code Block | ||
---|---|---|
| ||
if (u.value.length > 0) { var baseUrl = "/frevvo/web/tn/" + _data.getParameter('tn.id') + "/user/"+_data.getParameter('user.id') + "/app/"+_data.getParameter('app.id') + "/form/"+_data.getParameter('form.id'); im.value = '<img src="' + baseUrl + '/attachment/' + u.value+'/does_not_matter"/>'; } |
...