Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Section
Column
width75%

This chapter contains numerous real world samples of the custom dynamic behaviors you can add to your forms and workflows. Many of the business rules described below are easily created with the Visual Rule Builder. This eliminates the need for the designer to write JavaScript. The Visual Rule Builder provides the functionality to add business logic by simply selecting appropriate functions or controls from your forms/flows using a visual wizard.

The Visual Rule Builder provides the following functions


Use the Operators listed below to build the rule expression


Rules can still be written by manually adding JavaScript in order to build any degree of complex & powerful business logic and integrate with all or your Web Services and frevvo connectors.

Refer to the Visual Rule Builder chapter or watch this webinar for an overview of how to create dynamic forms/flows without writing code.

Calculate Totals

Forms are easier for your users with business logic that automatically calculates subtotals, total, etc..  Here are several common examples:

  • Expense Report Subtotals and Grand Totals.
  • Time Sheets Hours per task, per day and week
  • Purchase Order line Item Costs

Add two fields

Expand
titleThis example uses the sum function adds the values of two fields and displays the result in a Total field.

Your form has three Quantity controls named Q1, Q2 and T respectively. You want to add the values in Q1 and Q2 and display the result in the Total Quantity field. This rule will automatically fire whenever the user types something in Q1 or Q2 and will set the value of Total Quantity appropriately. However, it's important to ensure that the calculated value is valid with respect to the type of Total Quantity. For example, if Total Quantity was of type integer and the computed value of the expression was decimal (such as 1.5), then the rule would be attempting to set an invalid value in T. This is an error. The rule will set the value as requested, but will mark the field as invalid and take appropriate action such as disabling the submit button, displaying the control with a red background etc. Also, if controls are added to the form from the palette, it is important to ensure they have the correct type. For example, for a numeric calculation as described above, the controls should be of type Numeric (found in the palette).

You can use the sum function or just type Q1 + Q2 in the expression field

Section
Column

Action Wizard

Column

Rule List

Section
Column

Action Wizard

Column

Rule List


Multiply Price times Quantity and display results in a Total field

Expand
titleThis example multiplies Price times Quantity and displays the result in a Subtotal field.

Your form/flow has a Price, Quantity and Total Quantity controls. You want to multiply Price times Quantity and display the results in the Total field.

Section
Column

Action Wizard

Column

Rule List

Calculate a Subtotal

Expand
titleThis example computes Subtotals for all the rows in a Table

Imagine you have an Purchase Order workflow with a Table control. The Table has Price,Quantity and a Subtotal column. The fields are named Item_Price, Item_Quantity and Item_Subtotal. You want to multiply the Item_Price times the Item_Quantity and display the results in the Item_Subtotal fields for all the rows in the table. The Rule Builder automatically creates the code to handle adding/deleting table rows.

Section
Column

Action Wizard

Column
width50%

Rule List

Calculate a Grand Total

Expand
titleThis example calculates a Grand Total by adding the Subtotal values

Now you want to add a Grand Total field to your Purchase Order workflow. The Grand Total field contains the sum of the Subtotal fields in each row of the table. Add a Money control to your form/flow and name it Grand Total. Use the Rule Builder to create the rule. The Rule Builder automatically creates the code to handle adding/deleting table rows.

Section
Column

Action Wizard

Column
width50%

Rule List

Show or Hide Controls and Workflow Steps

Often forms/flows need fields that are only used depending on the answers to prior form fields. For example, if your form requires both a Shipping Address and Billing Address but the your form user has checked  "Shipping is the same as Billing Address" then it's nice to not clutter the form with the unnecessary Shipping Address input fields. You can use rules to hide the Shipping Address and show it only when the form user says they are different.

The easiest way to create a Show/Hide rule is to use the Visual Rule Builder. Here are common reasons for using Show/Hide:

  • Show/Hide a section
  • Show a Message to the user to alert them to either an error or success condition
  • Show a Details Text Area when as user clicks Yes to "Would you like to describe your issues in detail?"
  • Show a Signature or Signed Section when the workflow reaches the approval step.
  • Show/Hide a Tab on a Workflow Step

See the documentation for Data Sources and Schemas for details on implementing a Show/Hide rule with XSD controls.

Show the Shipping Address if it is different from the Billing Address

Expand
titleThis example shows the Shipping Address section if it is different from the Billing Addres

Your form contains a Billing Address section, a hidden Shipping Address section named S and a Radio control named B that asks the question - "Is the Shipping Address different from the Billing Address?" If the Billing and Shipping addresses are the same there is no need to clutter the form with the unnecessary Shipping Address input fields. You can use rules to hide the Shipping Address and show it only when the form user says they are different. This rule will automatically fire whenever the user checks or unchecks B and will show/hide the shipping address section S. In this example, you would typically set the checkbox B to be initially unchecked and the section S to be initially hidden.

Section
Column

Condition, Action and Else Action wizards

Column

Rule List

Show a Message based on Selections in Other controls

Expand
titleThis example shows a Message when specific options are selected in the Facility and CompanyFacility fields

This form has a radio control named Facility and a second radio control named CompanyFacility. This rule makes a message control named Msg visible depending on the selected options. If Boston is selected for the Facility control OR New York is selected for the the CompanyFacility control, the hidden message control will display. Use the Rule Builder to create this rule - remember to change the "and" to "or" in the Logic expression so the rule will execute if either condition is met.

Section
Column

Condition, Action and Else Action wizards

Column

Rule List

Show a Message if a control contains data

Expand
titleThis example shows a Message if there is a value in another control

This rule makes the message control nickNameThankYou visible when the user enters a value into the Nickname input text control. And then hides the message control if the user deletes the value in Nickname.

Section
Column

Column

Show Tabs on specified flow steps

Expand
titleThis example will Show a Hidden Tab on a Workflow Step

Step 1 of the flow has a Tab control with a tab named Employee and a second tab named Review. This rule makes a tab named Review visible only when the workflow is on the step named Manager Review(Step 2).



Section
Column

Condition, Action and else Action wizards

Column

 

Rule List

Show/Hide Submit & Cancel

This rule is not yet supported in the Visual Rules Builder and thus still requires some JavaScript.

You have a form with multiple tabs. The main tab contains the form and the other tabs contain reference information users may need when completing the form. You only want the submit and cancel buttons visible when the user is in the main tab. This rule hides the submit and cancel buttons when the reference tabs are selected. The control name of the main tab is MainTab. Be sure to select the Main Tab in the designer then save the form. This ensures the Main Tab will be selected when the form loads and the rule will run.

You can write the rule using the if...else conditional statement shown in the example on the left or the shortened syntax shown on the right:

Section
Column
Code Block
languagejs
if (!(MainTab.selected)) {
    Submit.visible = false;
    Cancel.visible = false;
} else {
   Submit.visible = true;
   Cancel.visible = true;
}
Column
Code Block
languagejs
 Submit.visible = Cancel.visible = (MainTab.selected);

 

 

Column
width25%

On this Page:

Table of Contents
maxLevel2

...

This is JavaScript behavior when calculating decimal point addition.  Use the built-in toFixed(n) function to truncate the result to n number of decimal places as shown in the rule below:

 

Section
Column
Code Block
var x;
x = (testone.value + testtwo.value + testthree.value + testfour.value + testfive.value + testsix.value);
LineTotal.value = x.toFixed(2);
Column

Another approach would be to assign Patterns that limit the number of decimal places to the fields.

Textarea Max Length

...

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
languagejs
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;

...

Set Options for a Checkbox based on Values Selected in another Checkbox

This rule is not yet supported in the Visual Rules Builder and thus still requires some JavaScript.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  This rule will take values selected in one checkbox control and populates those as options in a second checkbox control. For example, a checkbox control (Services) displays all available services. The second checkbox (Selected Services) will display as options the values selected in Services. One scenario you might use this is to customize an employee scheduling form. In Step 1 of the flow the Coordinator picks the offered services from the full Program Service list. In Step 2 the Employee sees only the smaller list to select from.

Code Block
var opts = [''];
 
for (var i = 0; i < ProgramService.value.length; i++ ){
  var v = ProgramService.value[i].replace(/_/g,"  ");
  opts[i] = ProgramService[i].value + "=" + v;
}
SelectedPS.options = opts; 
var event = form.load;

Image Added

Retrieving or Setting the Comment Property for  Selection Controls

This rule is not yet supported in the Visual Rules Builder and thus still requires some JavaScript.

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.

...

Use the today and timeofday functions in the Rule Builder to populate fields a Date field with the current date and a Time field with the current time on form load. Remember to select Date or Time from the Date Control Type dropdown.

Here is what the rule looks like in the Rule List

Use the built-in date/time method now function to set your date/time controls to the current date and time in the user's local timezone on formload.

...

.

Image Added

 

Note

The currentTime(), currentDate() and currentDateTime() will not work in a form.load rule unless you specify a timezone on the form's Url via the _formTz Url parameter. This is because the form server needs to know the timezone in which to return the date and time. If you do not specify a formTz the methods will return null and the control values will remain blank. For example &formTz=America/New_York will set the control values to the current date and time in the eastern timezone.

...

 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
languagejavascript
 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;
}

...

Imagine an airline reservation form where the number of traveler information sections displayed or the number of rows in a table 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. Min/Max for the section are set to 1 and 20 in the forms designer.

Code Block
languagejavascript
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;
    }
} 

...

  1. 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.
  2. 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
  3. 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.
  4. if the number of sections needed is less than the number of existing sections then set the minoccurs first.
  5. 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.
  6. This rule sets the Min/Max properties to he same values so the plus and minus icons are not visible. This prevents users from adding repeating items.

Entering "5" as the number of travelers, sets the minOccurs and maxOccurs to 5 and shows 5 information sections.

Repeat Item Initialization

...

Each column in a table has a label, help and hint property. These properties work at the column level and can be set dynamically with a rule created with the Visual Rule Builder. Here is an example:

Here is an example of setting the table column printable property using rule code. Line 1 will set the entire column's printable property to false; lines 2-4 show an example of how to make individual cells not printable. Keep in mind that the column setting will override the setting of individual cells.

Code Block
linenumberstrue
  Col2.printable = false;
  for (var i=0; i<Col2.value.length; i++) {
    Col2[i].printable = false;
  }

Show/Hide a Column in a Table

...

If you click on the Rule Code to see the JavaScript generated by the Rule Builder, you will notice:

  • The individual rows inside the CustomerTable are referred to in the rule as CustomerTableItem.
  • Notice the TableItem deletable property is set to false when a lowercase or capital Y is entered in the first column. This will remove the minus icon for that row of the table. The for loop cycles through the table rows until the Max# property is reached.

Code Block
  var event = form.load;
for (let i = 0; i < ContactCustomer.value.length; i++) {
  if ((ContactCustomer[i].value === 'Y') || (ContactCustomer[i].value === 'y')) {
    CustomerTableItem[i].deletable = false;
  } else {
    CustomerTableItem[i].deletable = true;
  }
}

...

Code Block
languagejs
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
Column

The number of Travelers is set to 5.

Column

The number of Travelers is set to 3.

...

Code Block
  // some VERY likely unique number
  var n = new Date().valueOf().toString();
  PONumber.value = n;

Unique Sequential ID

If you are using the frevvo Database Connector and an external database, you can generate unique sequential ids with a database table, a stored procedure and a business rule. Refer to Generate Unique Sequential Id example for the details.

Upload Control

The rules for he Upload Contorl are not yet supported in the Visual Rules Builder and thus still requires some JavaScript.

...

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
languagejavascript
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"/>';
}

...