C Web Form Rules Examples

This appendix provides multiple examples and use cases for using web form rules within a web form. For general information about form rules, see Working with Web Form Rules .

This appendix includes the following sections:

C.1 Calculate a Total

The following example assumes you have a form with three controls and you have assigned them Names N1, N2 and T respectively. When a user enters a value in either N1 or N2 you want to set the value of T to the sum of N1 and N2.

The rule would be written as

if (N1.value > 0 || N2.value > 0) {
    T.value = N1.value + N2.value;
}

This rule will automatically run whenever the user types something in N1 or N2 and will set the value of T appropriately. You can use any legal JavaScript operators in the expression such as subtraction or multiplication. However, it is important to ensure that the calculated value is valid in the context of type of T. For example, if T 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 will generate 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, and so on.

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.

C.2 Show/Hide a Billing Address

The following example assumes you have a form with two controls and you have assigned them names B and S respectively. B is a check box with a single option whose value is Yes. If checked the user wishes to enter a different billing address in S and you want to display S.

The form rule would be written as

if (B[0].value == 'Yes') {
    S.visible = true;
} else {
    S.visible = false;
}

This form rule will automatically run whenever the user checks or unchecked B and will show/hide the billing address section S. You can use any valid JavaScript expression to compute the visible property of S as long as it evaluates to a boolean true or false value. In this example, you would typically set the check box B to be initially unchecked and the section S to be initially hidden.

C.3 Show/Hide Message

In the following example, the form has a radio control named Facility and makes a message visible depending on the selected options.

if (Facility.value == 'Boston' || 
    CompanyFacility.value == 'New York')
{
    Msg.visible = true;
} else {
    Msg.visible = false;
}

C.4 Enable/Disable a Question

This example assumes you have a form with two controls and you have assigned them Names B and Q respectively. B is a check box with a single option - Yes. If checked the user is a smoker and you wish to ask an additional question in Q.

The rule would be written as

if (B[0].value == 'Yes') {
    Q.enabled = true; 
} else {
 Q.enabled = false; 
}

This rule will automatically run whenever the user selects or deselects B and will enable/disable the question in Q. Again, you could use any legal JavaScript expression to compute the enabled property of Q as long as it evaluates to a boolean true or false value.

In this example, you would typically set the check box B to be initially unchecked and the control Q to be initially disabled.

C.5 Compute Subtotals for Repeating Items

The following form rule is an example of working with repeating items. For example, if you have a form with a repeating section representing an Item that the user may purchase. Each section has a Price (with Name P), a Quantity (Name Q) and a Subtotal (Name S). There are multiple items on the page and the number of items on any given page is unknown. The price field is filled in automatically. When the user enters a value in the quantity field for any item, you wish to compute the subtotal.

The rule is written as follows:

for (var i = 0; i < S.value.length; i++) { 
  if (Q[i].value > 0) {
    S[i].value = Q[i].value * P[i].value; 
  } else { 
    S[i].value = 0; 
  } 
}

This rule will automatically run whenever the user enters a value in the quantity field for any item. It will compute the subtotal for each item, for which the quantity is greater than 0 and fill in the subtotal field for that item with the computed value. If a particular item does not have a quantity, the subtotal is not computed.

C.6 Compute an Invoice Total

The following form rule is an example of working with repeating items. It assumes you have a control named Total with Name T. You want to set the value of Total to be the total invoice price, which is the sum of all the computed subtotals above.

This rule is written as:

var tot = 0; 
for (var i = 0; i < S.value.length; i++) {
  tot = tot + S[i].value; 
} 
T.value = tot;

This rule runs whenever a subtotal is updated, for example, when it is updated through the rule above. It adds the values of all the subtotals to arrive at an invoice total. You must use a temporary variable to compute the total.

If you write the rule as:

T.value = 0; 
for (var i = 0; i < S.value.length; i++) {
  T.value = T.value + S[i].value; 
}

it will not work correctly. This is due to internal limitations in the way rules are evaluated. Note that this rule is working with controls inside a repeat control. To handle the case of a item being deleted from the repeat you require the following addition, assuming that the repeat control is named ExpenseRepeat. Table controls are repeats with a different layout. The same applies to the table controls. If your table is named Expense then the repeat is automatically named ExpenseRepeat.

if (ExpenseRepeat.itemRemoved) {;}

C.7 Textarea Max Length

This example form has a textarea control named 'Desc' where the user can enter up to a 500 character description. In HTML there is no way to set a maxLength on a textarea control. Due to this limitation, the textarea control does not have a maxlength property like the text control does.

It is possible to do this using a form rule. 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.

if (Desc.value.length > 500) {
  Desc.valid = false; 
} else {
  Desc.valid = true; 
}

You can customize the error message by adding the following line to your rule.

Desc.status = 'Invalid. Max 20 chars allowed and you have ' + Desc.value.length;

The error message will tell the user how many characters they are over the maximum allowed

C.8 Textarea Newline and 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 must replace newline characters with HTML breaks. This is due to 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.

The following example has a textarea control named Description and a hidden control named DF. The user types into the visible control named Description and a business rules converts the newline characters \n into html breaks.

var x = Description.value; 
x = x.replace(/\\n/g,"<br/>"); 
DF.value = x;

C.9 Dropdown Options

The following example automatically sets the option selected in one dropdown based on the option selected in another. This is often useful when you have a form with choices that were dynamically populated.

For example, imagine product choices which are descriptive text. When the user selects a product, your form must perform an action based on a product ID rather than the descriptive product text. A nice way to do this is to have the rule that dynamically populates the product choices dropdown also populate a product ID dropdown which remains an invisible control in the form. The product choices dropdown control was named P and the product ID dropdown control was named ID

The 1st rule "Load Products" populates both the visible and hidden dropdowns with options from a database.

Load Products: 
-------------- 
if (form.load) { 
eval('x=' + http.get('http://localhost:8082/database/products'));   
 
    var opts1 = []; 
    var opts2 = []; 
 
    for (var i=0; i < x.resultSet.length; i++) { 
        if (x.resultSet[i]) { 
            opts1[i] = x.resultSet[i].description; 
            opts2[i] = x.resultSet[i].productId; 
    } 
} 
 
 
Products.options = opts1; 
PID.options = opts2; 
Products.value = opts1[0]; // default to 1st product option 
PID.value = opts2[0]; 
}

C.10 Finding a Selected Options Index

The 2nd rule Select Product ID keeps the hidden PID dropdown synchronized with the visible Product description dropdown.

Select Product ID Rule: 
----------------------- 
if (Products.value.length > 0) 
{ 
    var i; 
    for (x in Products.options) {
        if (Products.value == Products.options[x]) 
            i = Products.options.indexOf(Products.options[x]); 
}

PID.value = PID.options[i] + ''; 
}

In v4 rules using hidden dropdowns to keep descriptive option labels visible to the user while keeping cryptic database values hidden are often no longer necessary. Dropdown options have values distinct from the human visible option labels. The above can now be achieved with a single simpler rule:

for (var i=0; i < x.resultSet.length; i++) { 
    if (x.resultSet[i]) { 
            opts1[i] = x.resultSet[i].productId+ '=' + x.resultSet[i].description; 
    } 
} 
Rdocnum.options = opts1;

Here is another rule that dynamically populates both the product choices and product ID dropdowns. This rule calls a REST Service which returns an object rather than the result set returned by the database connector as shown above. See the section on dynamic content for more details.

if (S.value.length > 0) {
    eval('x=' + http.get('http://localhost:8182/products/?category=' + S.value)); 
    P.options = x.products; 
    ID.options = x.ids; 
}

C.11 Synchronized Selects

The Product Search example above is often used in conjunction with a hidden select control.

Imagine that your database table contains a list of products. Each product has product description also a unique product ID. The user must select a product from a dropdown on your form. You want to populate the dropdown with the product descriptions. The users do not have to see or know the product IDs but you must use the ID as the key into the database for other selects. To do this add another hidden dropdown to the form and populate it with the IDs. This example has a visible dropdown name Products and an invisible dropdown named PID. See the rule above that populates these dropdowns dynamically from the database.

This rule below keeps the PID selected option in sync with the selected Product.

var i; 
for (x in Products.options) { 
// Determine the index of the selected product in the Products dropdown options 
if (Products.value == Products.options[x]) 
    i = Products.options.indexOf(Products.options[x]); 
}

 
// Changed the selected PID to match the selected Product 
PID.value = PID.options[i] + '';

C.12 Clearing Dropdown Options

This sample resets a dropdown option to the automatically added blank option.

For dropdowns added from palette controls and from schema, Oracle Web Forms automatically adds a blank option so the dropdown initially shows no choice by default. To reset the dropdown, set the dropdown control's value to null not the empty string. The empty string will not work since the empty string is not a valid option. This form resets the dropdown named size whenever the value of the product option changes.

if (product.value.length > 0) {  
    size.value = null; 
}

C.13 Default Option

When your options are set dynamically as shown below in a business rule, you cannot set a default in on the form designer. You must set the default in the rule.

If your options have <value>=<label> where value is different from label, make sure you set the <control>.value to <value> not <label> and not <value>=<label>

if (form.load) { 
    var cc = ['R=Red', 'B=Blue', 'G=Green'];
    Colors.options = cc;
    Colors.value = 'B';
}

C.14 Check Box Options - Assigning Color to Check Box Choices

Check box controls are different from all other Oracle Web Forms palette controls in that they are multi-select. Therefore the way to write rules with check box controls are in many ways similar to rules with repeat controls.

This rule has a check box controls with name colorPalette with the options: purple, green, blue, yellow, orange. The form also contains a text control with name colorChoice. This rule assigns colorChoice the choices selected from colorPalette.

var choices = ''; 
for (var i = 0; i < colorPalette.value.length; i++) 
{  
    choices = choices + colorPalette[i].value; 
} 
colorChoice.value = choices;

Notice that similar to repeat controls, due to an internal evaluation limitation, you must collect the choices in a variable inside the for loop. And then assign that control Name.value to that variable outside the for loop.

This rule is another example showing how check box controls are array types.

if (colorPalette.value.length > 0) 
{ 
    colorChoice.value = 'Thank you for choosing colors'; 
} 
else 
{ 
    colorChoice.value = 'Please choose colors...'; 
}

C.15 Check Box Options - Making a Control Visible/Invisible Based on Check Box Choices

This rule makes visible/invisible a control based on which check box options a user selects.

This form contains a multi select check box named Structures. If the user selects the option "Detached Garage" or "House", we want to make visible a text field named Details.

Again since a check box is multi select, it is handled as an array. The array will contain all selected (checked) options.

It is important to note that when a check box is added to the form from the palette and its options are multiple words containing spaces, the option array has converted each space character to the '_' character. We must make the comparison as shown below. Check box controls from schema do not have space replaced with '_'.

var found = false; 
for (var i = 0; i < Structures.value.length; i++) 
{ 
    if (Structures[i].value == 'Detached_Garage' || 
        Structures[i].value == 'House') { 
      found = true; 
      break; 
    } 
} 
if (found == true) { 
    Details.visible = true; 
} else { 
    Details.visible = false; 
    Details.value = null; 
}

Note that when we hide Details we also clear its value. This is because the user may have selected one of the Structures check boxes that made Details visible AND entered a value into Details. And then they may have changed their minds and deselect the option that caused Details to become visible. If you don't want the value entered into Details to be in your form submission, clear the value when hiding it.

C.16 Check Box Initialization

Since check box options are multi-select, in order to select multiple options using a rule you must use this syntax.

In this example CB is the name of a check box controls with the following options: red, green, blue. This rule selects all of the options.

CB.value = ['red', 'green', 'blue'];

To clear all checked option in the control named CB:

CB.value = [];

C.17 Displaying Selected Check Box Labels

In this example, the rule displays the labels of the check boxes the user selects.

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

C.18 Repeating Check Boxes

Check boxes inside controls must be treated as an array (each check box control's values) of check box option values which is inside another array (the repeating check box control itself).

This form example has a repeating section containing two controls -- Message, which is a text control and AreYouAttending, which is a check box control with a single option 'yes'. To access the selected options the syntax is:

AreYouAttending[i].value[0] == 'yes'

for (var i = 0; i < AreYouAttending.value.length; i++) 
{ 
    if (AreYouAttending[i].value[0] == 'yes') {
        Message[i].value = Name.value + 
               ' is attending event #' + i; 
    } 
}

C.19 Display a Message Control Inside a Repeat Control

If you put a message control inside a repeat control, you must add a rule to the message control to have the message repeat when a user clicks to add a new repeat item.

In the example below, the messages appear correctly in the first item, but a rule is necessary to have them appear when the user adds a second, third, or more items.

In the example below, the rule repeats both dynamic text (Contest Nomination For: [Name]) in the first message control and static text (By signing this consent form...) in the second message control.

if (Consent.itemAdded) 
{ 
    var index = Consent.itemIndex;
    ConsentNominationForMsg[index].value = 'Contest Nomination For: ' + ClubName.value + ' by ' + NominatorSName.value;
 
    ConsentMsg[index].value = 'By signing this consent form you hereby agree that it is acceptable to use a photo or video with your image.'; 
}

C.20 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:

var totalAssets = TotalAutoValue.value + TotalBankValue.value + TotalRealEstateValue.value;

BasicSummaryMsg.value =  
"<b>Name:</b> " + FirstName.value + " " + LastName.value + "<br/>" + 
"<b>Phone:</b> " + Phone.value + "<br/>" + 
"<b>Email:</b> " + EmailAddress.value;

if (MilitaryOrCivilian.value == 'Military') { 
//Military 
DetailedSummaryMsg.value =  
"<b>Military Info:</b><br/>" +  "Military ID: " + MilitaryID.value + "<br/>" + 
"Rank: " + Rank.value + "<br/>" + 
"CurrentTitle: " + CurrentTitle.value + "<br/>" + 
"Years of Service: " + YearsOfService.value + "<br/>"; 
} else if (MilitaryOrCivilian.value == 'Civilian') { 
//Civilian 
DetailedSummaryMsg.value =  
"<b>Civilian Info:</b><br/>" +  
"SSN: " + SSN.value + "<br/>" + 
"Current Employer: " + CurrentEmployer.value + "<br/>" + 
"Current Title: " + CurrentTitle2.value + "<br/>" + 
"Start Date: " + StartDate.value + "<br/>"; 
}

FinancialSummaryMsg.value = 
"<b>Total Assets:</b> $" + totalAssets + 
"<br/>" + "Total Bank Assets: $" + TotalBankValue.value + "<br/>" + 
"Total Real Estate Value: $" + TotalRealEstateValue.value + "<br/>" + 
"Total Auto Value: $" + TotalAutoValue.value + "<br/>";

Note when using field values from repeat controls you must use a javascript var and assign the concatenation to the var and then the var to the Oracle Web Forms message control value. For example imagine you have a message control named Summary and a repeat control named Account:

var acctSummary; 
for (var i = 0; i < Account.value.length; i++) { 
    if (Q[i].value > 0) { 
        acctSummary = acctSummary + 'Account #' + i + ': ' + Account[i].value + '<br/>'; 
    } 
} 
Summary.value = acctSummary;

C.21 Visible/Invisible

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.

if (nickName.value.length > 0 ) 
{ 
    nickNameThankYou.visible = true; 
} 
else 
{  
    nickNameThankYou.visible = false; 
}

C.22 Visible/Invisible Section

Often section controls contain many inner controls. For example imagine a form that contains a person's medical history. One of the questions on the form asks if the patient uses a hearing aid. If they answer yes, then you want to collect more details on their hearing aid usage such as left ear, right ear, bilateral; hearing aid brand; and so on. If they answer no then you want to hide all the questions specific to hearing aids. Also when they answer yes you want them to answer all the hearing aid related questions.

Avoid using message control inside of a section that contains other controls that you may want to make invisible. Since a message control always contains a value, it can cause a section, or other controls in a section, to become required, and this can disable the form's Submit button. If you must include a message control, place it outside the section. Another alternative is to write rules for the individual controls within a section to set them to visible/invisible or required/not required

Imagine this example form has a section named HearingAid. By default HearingAid visible is set to false in the form designer.

When they answer yes, you must set HearingAid.visible=true AND also each required field inside the section to field.required = true. If they then change the answer to no then another rule makes the HearingAid.visible=false also must set all field.required=true again. If the HearingAid section contains many child controls this rule becomes very long and tedious to write

We can simplify this by using the required property for sections. In the designer default all controls that must be answered inside HearingAid to required. Default the HearingAid section to not required and not visible. Your rule can be much simpler. By setting HearingAid.required=false all the inner controls recursively also become required=false.

if (useAid.value == 'no') {
    // Hide 
    HearingAid.visible = false; 
    HearingAid.required = false; 
} else { 
    // Show 
    HearingAid.visible = true; 
    HearingAid.required = true; 
}

C.23 Select Tab

This rule makes a specific tab the selected tab based on the choice of a radio control.

The radio is named SelectTab and has three options: person, auto, home. The tabs are named personTab, autoTab and homeTab. Tabs also can be select based on trigger controls or other input controls using the same method.

if (SelectTab.value.length > 0)
{ 
    autoTab.selected = false; 
    homeTab.selected = false; 
    personTab.selected = false;

    if (SelectTab.value == 'Auto') 
        autoTab.selected = true; 
    else if (SelectTab.value == 'Home') 
    homeTab.selected = true; else personTab.selected = true;
}

C.24 Next Tab

This form contains a trigger control at the bottom of each tab labeled "Next". When "Next" is clicked the trigger rule executes and makes the next tab the selected tab.

This assists the user in navigating through the form. The Tabs are named T1, T2, T3, T4. The trigger controls are named C1, C2, C3

// Navigate Tabs 
if (C1.clicked) { 
    T2.selected = true; 
} else if (C2.clicked) {
    T3.selected = true; 
} else if (C3.clicked) { 
    T4.selected = true; 
}

C.25 Expand/Collapse Section

This form has three sections. The first section is expanded and the 2nd and 3rd are collapsed. When the user files in the 1st section they click a "Next" trigger control which causes that section to collapse and the next section to expand.

The trigger controls are named next1 and next2 and the sections are named: step1, step2, step3. Try this membership form to see the rule in action.

if(next1.clicked) 
{ 
    step1.expanded = false; 
    step2.expanded = true; 
}

if(next2.clicked) 
{ 
    step2.expanded = false; 
    step3.expanded = true; 
}

C.26 Multiple Choice

This rule makes the appropriate input text controls visible depending on the choice a user makes in a radio option controls searchChoice.

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

C.27 Dynamic Options

Select control options (radios, check boxes, dropdowns, T/F) can be set dynamically using rules rather than statically using 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 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.

C.28 Triggers and Dynamic Options

This rule is executed when the user clicks the trigger controls with Name ''search''.

It then dynamically sets options on a dropdown list control with Name coffeeShopList.

if (search.clicked) 
{ 
    coffeeShopList.options = ['Koffee', 'Starbucks', 'Willoughbys', 'Dunkin Donuts']; }

Now replace the hard coded list of coffee shops with a rule that invokes an http.get. This must return an X-JSON header which containing a JSON object. The object is evaluated and assigned to the variable x. In this case the JSON object contains an options field of type array.

if (search.clicked) 
{ 
    eval('x=' + http.get('http://<webhost>/getCoffeeShopList'));  
    coffeeShopList.options = x.options; 
}

Note:

Triggers do not work in repeating items.

C.29 Value Change and Dynamic Options

This rule dynamically sets the options in a dropdown list based on the value selected in another form field. This form contains three fields named Products, Series and Model. The series options are set dynamically based on the product selection.

Also when a new product is selected we enable the series dropdown and both clear and disable the model dropdown. This form contains other rules which set the models based on the selected series. Look for the Oracle Web Forms Gallery form named HP Support - 2 under the dynamic forms keyword.

if (product.value == 'Laserjet Printers') 
{ 
    series.options = [' ', 'Laserjet5 series', 'Laserjet6 series']; 
    series.enabled = true; 
    model.options = []; 
    model.enabled = false; 
}

C.30 Dynamic Control Initialization

This rule handles the case of setting multiple control values based on the selection of a single dropdown control. It handles this case better than using a long if/else construct.

First add options to the dropdown named SalesRep in the format <value>=<label> where <value> will be used as an index key into an array of details about each person.

Megan=Megan Smith 
Jim=Jim Brown 
Nancy=Nancy Jones 
Brian=Brian Jones

Next write a rule that first sets up a javascript array with the contact information for each person. The rules then uses the dropdown value to index into the contantInfo array to set the details for the selected person into four other form controls.

var contactInfo = { 
    "" : {  
        name : "", 
        email : "", 
        phone : "", 
        cell : "" 
    }, 
    "Megan" : {  
         name : "Megan Smith", 
         email : MSmith@mycompany.com, 
         phone : "(203) 694-2439 Ext. 516", 
         cell : "(203) 337-3242" 
    }, 
    "Jim" : {  
        name : "Jim Brown", 
        email : jim@comcast.net, 
        phone : "203-208-2999", 
        cell : "" 
    }, 
    "Nancy" : {  
        name : "Nancy Jones", 
        email : nancy@snet.net, 
        phone : "203-208-2991",  
        cell : "" 
    }, 
    "Brian" : {  
        name : "Brian Jones", 
        email : BJones@mycompany.com, 
        phone : "203-748-6502", 
        cell : "" 
    } 
};
 
var repId = SalesRep.value;
SalesRepName.value = contactInfo[repId].name; 
SalesRepEmail.value = contactInfo[repId].email; 
SalesRepPhone.value = contactInfo[repId].phone; 
SalesRepCell.value = contactInfo[repId].cell;

C.31 Verify User

This rule executes when the user enters a value into the Username text field. It invokes a URL that returns a JSON object that has a boolean field name ''exists'' that is set to true if the user already exists. If the user already exists, this rule then sets the value of a message control, makes that message control visible on the form and sets the Username valid property to false so that Username field displays as invalid to guide the user to make a correction.

if (U.value.length > 0) { 
    eval('x=' + http.get('http://<webhost>/uniqueUser?username=' + U.value)); 
    if (x.exists) { 
        M.value = 'User: ' + U.value + ' already exists'; 
        M.visible = true; 
        U.valid = false; 
    } else { 
        M.visible = false; 
} 
}

C.32 Calculate Net Worth

This form contains two rules. One is adding values entered into a column of assets and a column of liabilities and calculating netWorth. The 2nd rule is checking the value of netWorth and displaying an error message and marking netWorth invalid if liabilities exceed assets since the form designer does not want the form to be submitted in that state.

if (netWorth.value < 0) 
{ 
    assetsExceedLiabilitiesMsg.visible = true; 
    netWorth.valid = false; 
} 
else 
{ 
    assetsExceedLiabilitiesMsg.visible = false; 
    netWorth.valid = true; 
}

When a rule sets <control>.invalid the control background turns red and the submit button greys out just as if the user had entered an invalid value into a phone control. Oracle Web Forms treats it exactly the same way. This is a good way to dynamically control your form's valid state.

C.33 Dates and Times

Working with dates and times is very common in most forms. The samples below show you how to create the most common business logic with dates and times.

Oracle Web Forms dates can be set in the user's local timezone by using the built-in date, time and date/time methods such as frevvo.currentDateTime(form). Some of the samples below use the javascript Date() object. Since business rules run on the form server these dates will be in the timezone where the form server was installed. There are techniques below to convert to different timezones as necessary.

The Date/Time control must be initialized using array syntax from a business rule. For example to initialize a Date/Time control named DtTm to January 1st, 2012 at 4:20 am.

DtTm.value = ['5/15/2012', '4:20']

Rules initializing dates and time will not work in a form.load rule unless you specify a timezone on the form's Url using the _formTz URL parameter. This is because the form server must 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, to specify Eastern time: &_formTz=America/NewYork.

C.33.1 Duration

This form initializes the hospital discharge date using a rule, and when the user enters the admission date a 2nd rule calculates the number of days the patient stayed in the hospital.

// Calculate Hospital Stay Duration 
if (A.value != '' && D.value != '') { 
    var da = A.value.split('-'); 
    var Ams = new Date(da[2],da[0]-1,da[1]); 
    da = D.value.split('-'); 
    var Dms = new Date(da[2],da[0]-1,da[1]);

    if (Ams > Dms) { 
        Days.value = 'Discharge date must be after Admission Date'; 
    } else { 
        Days.value = (Dms - Ams) / (1000*60*60*24) + ' days'; 
    } 
}

C.33.2 Today's Date and Time

Use Oracle Web Forms's built-in date and time methods to set your date, time, and date/time controls to the current date and time in the user's local timezone.

if (form.load) {
  Tm.value = frevvo.currentTime(form);
  Dt.value = frevvo.currentDate(form);
  DtTm.value = frevvo.currentDateTime(form);
}

The currentTime(), currentDate() and currentDateTime() will not work in a form.load rule unless you specify a timezone on the form's Url using the _formTz Url parameter. This is because the form server must 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.

C.33.3 Date/Time Stamp

This rule sets a control named Signature to the value of a control named Name plus a date/time stamp. Note that it is better to use the Oracle Web Forms built-in date and time methods if you want to set the date to the user's local timezone. The following method will set the date to the form server's timezone.

var today=new Date() 
var m = today.getMonth() + 1; 
var d = today.getDate(); 
var y = today.getFullYear(); 
var h = today.getHours(); var min = today.getMinutes(); var todayStr = m + '-' + d + '-' + y + ' ' + h + ':' + min; Signature.value = 'Signed by ' + Name.value + ' on ' + todayStr;

C.33.4 Invalid if Before Today

This rule makes the date control invalid if the date entered isn't before today's date.

var today = new Date(); 
var bd = DOB.value.split('-'); 
var bd_date = new Date(bd[0],bd[1]-1,bd[2]);

if (bd_date.getTime() > today.getTime()) { 
    MyMsg.value = 'Birth Date must be earlier than today!!!!';   
    DOB.valid = false; 
} else { 
    MyMsg.value = 'This is a good Birth Date: ' + DOB.value; 
DOB.valid = true; 
}

C.33.5 Date Less than 14 Days from Today

This rule checks that the date entered into a control named AppointmentDate is no more than 14 days greater than today's date.

var date1 = DateUtil.today(); 
var date2 = Appointment.value; 
date1 = date1.split("-"); 
date2 = date2.split("-"); 
var sDate = new Date(date1[0]+"/"+date1[1]+"/"+date1[2]); 
var eDate = new Date(date2[0]+"/"+date2[1]+"/"+date2[2]); 
var DaysApart = Math.round((eDate-sDate)/86400000);
 
if (DaysApart > 14) { 
    Appointment.status = "Date should be within 14 days from today's date."; 
} else if (DaysApart < 0) { 
    Appointment.status = "Date should not be earlier to today's date."; 
}

C.33.6 Date Less than 30 Days Ago

This rule checks that the date entered into a control named EventStartDate is 30 days or less from today.

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]+"/"+date2[1]+"/"+date2[2]); 
    var days = Math.round((eDate-sDate)/86400000);
 
if (!eval(parseInt(days) > parseInt(-30))) { 
    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; 
}

C.33.7 Central Timezone adjusted for Daylight Savings

This rule adjust today's date in UTC timezone to Central timezone and adjust for daylight savings time. This additional conversion is most commonly required for Online users as the javascript Date() and Oracle Web Forms' DateUtil.today() both return today's date in UTC timezone.

// Converts UTC to either CST or CDT 
if (form.load) 
{ 
    var today = new Date(); 
    var DST = 1; // If today falls outside DST period, 1 extra hr offset 
    var Central = 5; // Minimum 5 hr offset from UTC 
    // Is it Daylight Savings Time? 
    // 
    var yr = today.getFullYear(); 
    // 2nd Sunday in March can't occur after the 14th 
    var dst_start = new Date("March 14, "+yr+" 02:00:00"); 
    // 1st Sunday in November can't occur after the 7th 
    var dst_end = new Date("November 07, "+yr+" 02:00:00"); 
    var day = dst_start.getDay(); // day of week of 14th 
    // Calculate 2nd Sunday in March of this year 
    dst_start.setDate(14-day); day = dst_end.getDay(); // day of the week of 7th 
    // Calculate first Sunday in November of this year dst_end.setDate(7-day); 
    // Does today fall inside of DST period? 
    if (today >= dst_start && today < dst_end) { DST = 0; 
} 
 
    // Adjust Date for Central Timezone 
    today.set Hours(today.getHours() - Central - DST);   
 
    var m = today.getMonth() + 1; 
    var d = today.getDate(); 
    var da = today.getDay(); 
    var y = today.getFullYear(); 
    var h = today.getHours(); 
    var min = today.getMinutes(); 
    if (min < 10) { min = '0' + min;} 
    var timezone = ['CDT', 'CST']; 
    var dom = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 
               'Thursday', 'Friday', 'Saturday']; 
    var todayStr = dom[da] + ' ' + m + '-' + d + '-' + y + ' ' + h + ':' + min + ' ' + timezone[DST];  
 
    DateTime.value = todayStr; 
}

C.33.8 Hours > = 4 and < = 6 Apart

This rule makes sure the end time is at least 4 hours great then the start time but no more then 6 hours later then the start time. Also start time must be on or after 1:00. The times must be entered in military units. TS is the name of the Time Start control and TE is the name of the Time End control.

  • Use Text controls for the start and end times

  • Use this pattern in the control to ensure valid military times 1:00 or greater: ([1-9]|1[0-9]|2[0-4]):([0-5][0-9])

if (TS.value.length > 0 && TE.value.length > 0) { 
    var sTime = TS.value.split(':'); 
    var sHour = sTime[0]; 
    var sMin = sTime[1]; 
    var sMins = sHour * 60 + parseInt(sMin);
 
    var eTime = TE.value.split(':'); 
    var eHour = eTime [0]; 
    var eMin = eTime [1]; 
    var eMins = eHour * 60 + parseInt(eMin);

    if ((eMins - sMins) < 4*60 || (eMins - sMins) > 6*60) 
    { 
        TE.valid = false; 
    } else { 
    TE.valid = true; 
    }
}

C.33.9 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 name Tm;

// Both set the control name Tm to the same time
Tm.value = '8:30 pm'; // uses am/pm notation
Tm.vallue = ' 20:00'; // uses military time
 
// Initialize a date/time requires an array syntax
DtTm.value = ["Aug 1, 2001", "10.00"];
 
// Copying values
Tm2.value = Tm.value;
Dt2.value = Dt.value;
DtTm2.value = DtTm.value;

C.34 Tenants, Roles and Users

Oracle Web Forms has several built-in methods that enable you to access information about your form server such as the list of tenants; users in a tenant; and roles in a tenant. Some of these methods return a boolean true/false value. Others return a JSON string. Here is a sample of how to use these methods.

if(form.load)
{
  eval('x=' + frevvo.listTenants());
  Tenants.options = x.tenants; // Init a dropdown list of all tenants on this form server
}


if(tenant.value.length > 0)


 // Check if a tenant already exists
 if (frevvo.isUniqueRoleId(role.value, tenant.value) == true) {
    ErrMsg.value = 'The role ' + role.value + ' already exists in tenant ' + tenant.value;
  }
  // Init dropdown with all tenant users
  eval('x=' + frevvo.listUsers(tenant.value));
  Users.options = x.users;
  // Init dropdown with all tenant roles
  eval('x=' + frevvo.listRoles(tenant.value));
  Roles.options = x.roles;
  // Init dropdown will all tenant roles except admin roles
  eval('x=' + frevvo.listRoles(tenant.value, false));
  RolesNA.options = x.roles;
}
// Verify that a role already exists in the tenant
if(role.value.length > 0)
{
  t.value = frevvo.isUniqueRoleId(role.value, tenant.value);
  if (frevvo.isUniqueRoleId(role.value, tenant.value) == false) {
    ErrMsg.value = 'The role ' + role.value + ' already exists in tenant ' + tenant.value; 
  }
}

C.35 Repeat Item Added

This rule executes when a new item is added to a form.

Imagine your form contains a repeating section named Employee with name E. Note that the name E is set on the control and not on the Section control. The Employee section control contain many controls such as Name, Phone, and so on, as well as a dropdown control labeled Manager with named M. It also contains a radio control labeled Employee Shift named ES whose options have been set to 'Day' and 'Evening'.

Oracle Web Forms will execute this rule each time a user clicks "+" on the form to add a new item. We want to the Employee Shift ES to default to the value 'Day', and to populate the Manager dropdown dynamically with values from the Oracle Web Forms Database Connector.

Typically, a form will have a form.load rule to initialize dropdown options for the first item visible on your form.

if (form.load) 
{ 
    var baseURL = 'http://www.myhost.com:8080/database/';

    // Manager Dropdown 
    eval('x=' + http.get(baseURL + 'Manager'));
    var opts = ['']; // default 1st option to blank 
    for (var i=0; i < x.resultSet.length; i++) { 
        if (x.resultSet[i]) { 
            opts[i+1] = x.resultSet[i].lastname+ ", " + x.resultSet[i].firstname; 
    } 
}

//  item index 0 is on the form by default 
M[0].options = opts; 
ES[0].value = 'Day'; // default the employee shift to Day 
}

When a new item is added as a result of a user clicking the "+" icon, we save the overhead of going back to the database to retrieve dynamic options.

if (E.itemAdded) 
{ 
var index = E.itemIndex; // which item is this in the list
 
    // No need to go back to the database for options. 
    // We already retrieved them in form.load rule for  item index 0 M[index].options = M[0].options; ES[index].value = 'Day'; // default the employee shift to day }

Tables are repeats. The same rule can be written for a table control. The name of a table's repeat is always <TableName>Repeat. For example if you name your table Children, the repeat is named ChildrenRepeat.

C.36 Repeat Item Added - Collapse Other Items

This rule executes when a new item is added to a form. This form contains a repeating section with a templatized label.

You can collapse the other items when adding a new item to keep the list small and grid-like. Medrepeat is the name of the repeatcontrol. Medication is the name of the section control inside the repeat.

if (MedRepeat.itemAdded) 
{ 
    var index = MedRepeat.itemIndex; 
    for (var i = 0; i < Medication.value.length; i++) { 
        if (i != index) 
            Medication[i].expanded = false; 
        else 
            Medication[i].expanded = true;  
    } 
}

C.37 Tables

Tables are identical to controls when referenced in business rules. Tables are a grid layout of repeating items

. All the rule examples in this chapter that discuss s apply also to tables. The one important note is that you cannot explicitly name the control inside your table. The control inside a table is automatically named as <TableName>. For example a table named Expense automatically has a control named Expense. The rule Expense.itemAdded and Expense.itemIndex references an item added to your table and that item's index respectively.

C.38 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.

Rules using itemAdded only execute for repeat items added when the user clicks +, and for those added from an initial instance document (See Document URIs). It does '''not''' execute for those items that you have added to your form in the Form Designer. You can either add defaults directly through the form designer or add a 2nd rule to your form as follows.

These two rules together initialize the dropdown fields inside a control that is already in the form through the Form Designer, as well as those added each time a user clicks "+" on the control to add a new item. These controls are initialized based on a value set in another field.

'''1st Rule - Default Items''' 
if (form.load) 
{ 
    // The form contains two repeat items by default.
 
    if (department.value == 'Marketing') { 
        Managers[0].options = ['Joe', 'Mary', 'Stan', 'Cindy'];
        Managers[1].options = ['Joe', 'Mary', 'Stan', 'Cindy']; 
} 
    if (department.value == 'Sales') {
        Managers[0].options = ['Lou', 'George', 'Wendy']; 
        Managers[1].options = ['Lou', 'George', 'Wendy'];  
    } 
}

'''2nd Rule - Items Added''' 
if (Erepeat.itemAdded) 
{
    var index = Erepeat.itemIndex; // which item is this in the list  
    ES[index].value = 'Day'; // default the employee shift to day

    // Use options already selected in form.load rule 
    Managers[index].options = Manager[0].options; 
}

This rule is useful in a workflow where you want to make a the tab named Review visible only for the workflow activity named Manager Review.

if (form.load) { 
    if (_data.getParameter('flow.activity.name') == 'Manager Review') { 
Review.visible = true; 
    } 
}

C.39 form.unload

Rules can be used to finalize field values after the users clicks the form's submit button but before the Form and Doc Action execution. Rules using form.unload are triggered when the form user clicks the submit button and for workflows when the user clicks continue to go to the next activity or finish to complete the flow.

One common example use is for an order form order number. You may only want to assign a unique sequential order number to each order submission. You could initialize the form's order number when the form loads using form.load. However if someone starts filling in the order form but never submit it you do not want to consume the next order number in sequence if it will never be used. Using form.unload you can assign the number after the submit button click but before the form data is submitted.

Here OrderNum is the name of a invisible control.

if (form.unload) 
{ 
    eval('x=' + http.get('http://<webhost>/json/getNextOrdernum'));  
    OrderNum.value = x.num;
}

C.40 Unique ID

Forms such as invoices, bills of lading, and so on often must be stamped with a unique ID. The Sequential Number example is one approach, however it has some limitations. One is that you must guarantee that only one person at a time is filling out your form.

Here is a simpler method if your unique IDs do not have to be sequential. The data named form.id is guaranteed to be unique for every new form instance. You can just use it as follows:

if (form.load) 
{ 
    InvoiceNum.value = _data.getParameter('form.id'); 
}

C.41 Repeat Item Initialization

The rule above was one example of initializing a newly added repeating control with a default list of options. This same concept is useful if you want to initialize a repeating control's value.

When you add a repeat control to your form in the Form Designer you can set a default value in any of those repeating controls visible in the designer. However when the user clicks "+" while using the form to add an additional item the default entered in the Form Designer is not automatically used in this new item. In order to accomplish this you can add a simple rule as follows:

This rule initializes the value of one of the fields in the repeat control to a default of '0'. RepeatTrack is the name of the repeat control contained the input control named albumOnly. This rule executes each time a new RepeatTrack item is added when the user clicks "+".

Note:

ItemAdded and itemIndex are properties of the Repeat control.

if (RepeatTrack.itemAdded) 
{ 
    var index = RepeatTrack.itemIndex; 
    albumOnly[index].value = 0; 
}

To initialize repeat items already on your form in the Form Designer by default, either enter your initial default values directly into the in the Form Designer or add this rule.

if (form.load) 
{ 
    for (var i=0; i < albumOnly.value.length; i++) { 
        albumOnly[i].value = 0; 
    } 
}

This rule takes into account a repeat where min > 1. If min is 0 or 1, you can simplify this further by removing the from loop and simply have albumOnly[0].value = 0 inside the if (form.load).

C.42 ItemAdded by Init Doc

ItemAdded also executes when Oracle Web Forms adds items found in an init doc. You may want to only initialize items added when the user clicks "+" on the form and not those added from an initial document.

This form contains a Mailing Label that repeats. Each label requires a unique ID assigned. However, after the form is submitted the assigned IDs are saved in the database through the form's Doc URI. When the form loads it adds items automatically from rows in the database. They already have assigned IDs. We only have to assign new IDs in the sequence when the user manually adds a new Mailing Label by clicking the "+" button on the form. MLrepeat is the name of the Mailing Label repeat. MLmid is the name of the ID field in the form.

if (MLrepeat.itemAdded)
{
  var index = MLrepeat.itemIndex;
  // This rule is fired both when the user clicks "+"
  // and when frevvo adds items found in the init doc.
  // Need to assign new mid only when user clicks "+"

  // New items added via "+" will have a zero length value.
  if (MLmid[index].value.length == 0) {
    // Assign unique ID to label so it can be referenced
    // in RI Mailing Labels field
    // Count the number of existing mailing labels on the form
    var maxId = 0;
    for (var i=0; i < MLmid.value.length; i++)
    {
      if (MLmid[i].value > maxId) {
        maxId = MLmid[i].value;
      }
    }
    var next = parseInt(maxId) + 1;
    MLmid[index].value = next.toFixed(0);
  }
}