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; } } |
...
Code Block |
---|
var x, x1, x2; if (Num.value > 0) { var nStr = Num.value.toFixed(2); nStr += ''; x = nStr.split('.'); x1 = x[0]; x2 = x.length > 1 ? '.' + x[1] : ''; var rgx = /(\d+)(\d{3})/; while (rgx.test(x1)) { x1 = x1.replace(rgx, '$1' + ',' + '$2'); } Message.value = x1 + x2; } |
Textarea Max Length
In html there is no way to set a maxLength on a textarea control. This is why the textarea control does not have a maxlength property like the text control does. It is possible to do this via a business rule. This example form has a textarea control named 'Desc' where the user can enter up to a 500 character description. On this control we also set the ErrorMsg property to the string 'You must limit your description to 500 characters'. This message is automatically displayed when the description control is set to invalid by the following business rule.
Code Block |
---|
if (Desc.value.length > 500) {
Desc.valid = false;
} else {
Desc.valid = true;
} |
You can even customize the error message by adding this line to your rule. Now the error message will tell the user how many characters they are over the maximum allowed.
Code Block |
---|
Desc.status = 'Invalid. Max 20 chars allowed and you have ' + Desc.value.length; |
...
Required Field Status in Accessible Forms
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;
} |
If the rule is written this way, it will fill the message control with the errmsg from the invalid text control.
Code Block | ||
---|---|---|
| ||
if (!t.valid) {
if (t.value.length === 0) {
m.value = "You can't leave this empty."
} else {
m.value = t.status;
}
} |
Textarea Max Length
In html there is no way to set a maxLength on a textarea control. This is why the textarea control does not have a maxlength property like the text control does. It is possible to do this via a business rule. This example form has a textarea control named 'Desc' where the user can enter up to a 500 character description. On this control we also set the ErrorMsg property to the string 'You must limit your description to 500 characters'. This message is automatically displayed when the description control is set to invalid by the following business rule.
Code Block |
---|
if (Desc.value.length > 500) {
Desc.valid = false;
} else {
Desc.valid = true;
} |
You can even customize the error message by adding this line to your rule. Now the error message will tell the user how many characters they are over the maximum allowed.
Code Block |
---|
Desc.status = 'Invalid. Max 20 chars allowed and you have ' + Desc.value.length; |
Textarea newline vs break
Users typically enter multi-line text into textarea controls. If you want to display that text in an html context, for example on a web page or in an html formatted email or in your form's Form Action display message you will need to replace newlines with html breaks. This caused by the fact that line breaks entered into a web form textarea are represented by a single newline character \n while line breaks in an html context are represented by the html break characters.
...
Code Block |
---|
if (EventStartDate.value !== "") { var date1 = DateUtil.today(); var date2 = EventStartDate.value; date1 = date1.split("-"); date2 = date2.split("-"); var sDate = new Date(date1[0]+"/"+date1[1]+"/"+date1[2]); var eDate = new Date(date2[0]+"); var sDate = new Date(date1[0]+"/"+date1[1]+"/"+date1[2]); /"+date2[1]+"/"+date2[2]); var days = Math.round((eDate-sDate)/86400000); if (!eval(parseInt(days,10) > parseInt(-30,10))) { EventStartDate.valid = false; EventStartDate.status = "The date entered can only go back a maximum of 30 days from the current date. Please try again."; } else { var eDateEventStartDate.valid = new Date(date2[0]+"/"+date2[1]+"/"+date2[2]); var days = Math.round((eDate-sDate)/86400000); if (!eval(parseInt(days,10) > parseInt(-30,10))) { EventStartDate.valid = false; EventStartDate.status = "The date entered can only go back a maximum of 30 days from the current date. Please try again."; } else { EventStartDate.valid = true; } } |
Add Years, Months or Days to a Date
Here is a rule that will add 3 years to a given date. For example, to calculate the expiration date of a three year contract by adding three years to the starting date, your form could have two date controls, one used to enter the starting date and the other to show the contract expiration date. This rule will take the date from the StartingDate field, add 3 years to it and populate the result in a field named ExpirationDate.
Code Block |
---|
if (StartDate.value.length > 0) { var dt = StartDate.value; ExpirationDatetrue; } } |
Add Years, Months or Days to a Date
Here is a rule that will add 3 years to a given date. For example, to calculate the expiration date of a three year contract by adding three years to the starting date, your form could have two date controls, one used to enter the starting date and the other to show the contract expiration date. This rule will take the date from the StartingDate field, add 3 years to it and populate the result in a field named ExpirationDate.
Code Block |
---|
if (StartDate.value.length > 0) {
var dt = StartDate.value;
ExpirationDate.value = frevvo.addToDate(dt,'y','3');
} |
This rule adds 1 month to the Start Date:
Code Block |
---|
if (StartDate.value.length > 0) {
var dt = StartDate.value;
ExpirationDate.value = frevvo.addToDate(dt,'m','1');
} |
This rule adds 11 days to the Start Date:
Code Block |
---|
if (StartDate.value.length > 0) {
var dt = StartDate.value;
ExpirationDate.value = frevvo.addToDate(dt,'d','11');
} |
These functions can be used with Date and Date/Time controls.
Setting a Future Date
You can write a rule using the addToDate method to calculate a future date. The example code executes when the form loads. It uses the DateUtil.today() method to populate the control named D1 with the current date. This method returns today's date in the format 'yyyy-mm-dd' instead of 'mm-dd-yyyy', making it compatible with utility methods such as addToDate(). The rule then
- adds one month to the current date to populate the control named D2.
- adds one day to the current date to populate the control named D3.
- adds one year to the current date to populate the control named D3.
Column |
---|
Column | |||||||
---|---|---|---|---|---|---|---|
|
This rule adds 1 month to the Start Date:
Code Block | ||
---|---|---|
if (StartDate.value.length > 0) {
var dt = StartDate.value;
ExpirationDate
|
This rule adds 11 days to the Start Date:
Code Block | |||
---|---|---|---|
if (StartDate.value.length > 0) {
var dt = StartDate.value;
ExpirationDate
|
These functions can be used with Date and Date/Time controls.
Calculate a Date based on a five day work week
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; 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 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 named TravelRepeat 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. Min/Max for the section are set to the default values in the forms designer.
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 because the table needs to increase.
- if 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.
- 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 repeating items.
Entering "5" as the number of travelers, sets the minOccurs and maxOccurs to 5 and shows 5 information sections.
...
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; } } |
...
For example, lets say you have a form that collects how many travelers are planning to travel. When the user enters a number of travelers, the table will populate with the same number of rows as travelers and populate the column for Traveler ID with an ID number. The form will adjust if the number of travelers is changed. travelers and populate the column for Traveler ID with an ID number. The form will adjust if the number of travelers is changed.
You can leave the default values for the Min/Max properties of the Table in the Forms designer or set them to any values provided the min value < max value and the max value > min value.
In this scenario, it is best practice to write 1 rule to handle the table, logic to loop through the rows of the table and itemadded for when another row is added to the table.
...
- 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 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.
...
A section in a repeat will behave differently than a table row when using a rule to set the valid property. For Example, drag and drop a table control into your form. Name it T. Then drag and drop a section into the same form. Name it S. Add a control to the section. Name the control C. Drop the section into a repeat named R. Add this rule to the form.
Clearing Values in a Table
This rule clears the values from all rows in a table. Notice the For loop that iterates over all the rows. Inside the loop a null value is assigned to all the columns in the table row.
Code Block | ||
---|---|---|
| ||
for (var i = 0; i < Col0.value.length; i++) {
Col0[i].value = null;
Col1[i].value = null;
Col2[i].value = null;
} |
You cannot clear an entire table from a rule.
form.load
Rules can be used to initialize field values. This is a very useful feature and is often used to dynamically populate dropdown options from a database. Rules using form.load are triggered when a form first loads and when a workflow is loaded from a task list.
...
Code Block |
---|
/*member num */ var x; if (form.unload) { eval('x=' + http.get('http://(your webhost)/json/getNextOrdernum')); OrderNum.value = x.num; } |
Info |
---|
Refer to this topic for the details about a change in behavior that has been implemented for Forms only. |
Geo Location
Rules can be used to save a snapshot of location information of any form. For example, an insurance company may want to capture the GPS location of their representatives filling out a form used for audit purposes. The designer can use the Geo Location feature in conjunction with rules like the ones shown in the examples below to accomplish this. When the form loads in the browser, the user will be prompted by to allow/disallow the use of location services. If permission is granted, the position will be calculated and server will be updated via an Ajax which causes the rule to fire. If the user denies permission or there is a timeout, the server will get an Ajax with an error.
...
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"/>'; } |
...