Options list

From pmusers
Jump to: navigation, search

Dynamically changing the list of options

This documentation provides three ways to dynamically change the list of available options in a Dynaform field (dropdown box, suggest box, radio button or checkgroup).

1. Use an SQL query with a dependent field

The recommended way to dynamically add or remove options from dropdown boxes, suggest boxes, radio buttons and checkgroups is to create an dependent field query, which will add or remove options from the list, depending on the value entered in other fields.

For example, a company wants to offer services to its clients, but those services depend on the type of client. A Dynaform contains a dropdown box with the ID "clientType", which has the following list of options:

KEY              |  LABEL
----------------------------------
large_business   |  Large business 
single_person    |  Single person
contractor       |  Contractor

Depending on which type of client is selected, the list of options will change in a radio button below with the ID "selectService".

A PM Table is constructed which holds the available options which will be listed in the "selectService" radio button. For example, the following PM_TABLE named PMT_CLIENT_SERVICES holds the list of available options for the radio button:

ID   | SERVICE_KEY    | SERVICE_LABEL     | CLIENT_TYPES
----------------------------------------------------------------------------------
1    | accounting     | Accounting        | large_business
2    | planning       | Business planning | large_business,single_person
3    | legal          | Legal services    | large_business,single_person
4    | catering       | Catering          | large_business,single_person,contractor

If the client is a large business then all the services are offered. If the client is a single person, then legal services, business planning and catering are offered. If a contractor, then only catering is offered.

Then, use the following SQL query in the "selectService" radio button, to limit which options are displayed:

SELECT SERVICE_KEY, SERVICE_LABEL FROM PMT_CLIENT_SERVICES WHERE CLIENT_TYPES LIKE CONCAT('%', @@clientType, '%')

2. Use an SQL query and JavaScript to filter the list

The first method list above is the easiest way to filter the list of available services, but the information to filter the list has to be included in the database table. If wishing to use JavaScript to determine the options for each type of client, then add a text field with the ID "servicesList". Then, use the following SQL query in the "selectService" radio button:

SELECT SERVICE_KEY, SERVICE_LABEL FROM PMT_CLIENT_SERVICES WHERE SERVICE_KEY IN (@#servicesList)

Finally, add the following JavaScript code to the Dynaform to populate the list in the "servicesList" field:

//hide the "servicesList" field when the Dynaform loads so the user won't see it:
$("#servicesList").hide();

function setServicesList(clientType) {
   var list = '';
   if (clientType == "large_business") {
      list = "'accounting','planning','legal','catering'";
   }
   else if (clientType == "single_person") {
      list = "'planning','legal','catering'";
   }
   else if (clientType == "contractor") {
      list = "'catering'";
   }
   
   $("#servicesList").setValue(list);
}   
   
//execute when user changes a client type:   
$("#clientType").setOnchange(function(newVal, oldVal) {
   setServicesList(newVal);
});

//execute when the Dynaform loads:
setServicesList( $("#clientType").getValue() );

Note: The "servicesList" field must be a text field, because hidden fields can't be used in dependent field queries.

3. Use JavaScript to modify the model information for the field

It is recommended that either a source variable or an SQL query be used to modify the list of options in a dropdown, suggest, checkgroup or radio, as shown in the above examples. However, if the list of options cannot be known beforehand, such as allowing a user to dynamically add options to the list while filling out the form, then JavaScript needs to be used to modify the list of options in the field's model.

The mergeRemoteOptions() function is used by ProcessMaker to add an array of options which were returned by an SQL query to the end of the list of fixed options which were set in the options property of a dropdown, suggest, checkgroup or radio:

getFieldById("field-id").model.mergeRemoteOptions( 
  [
    {
      value: "value1", 
      label: "label1"
    },
    { 
      value: "value2", 
      label: "label2"
    },
    ...
  ] 
)

For example, to add a single option to the "selectService" radio button:

getFieldById("selectService").model.mergeRemoteOptions([{value:"cleaning", label:"Cleaning Service"}])

The problem is that mergeRemoteOptions() will overwrite all the existing options which were added by an SQL query. If needing to preserve the list of existing options, then add the new option to the end of the model.attributes.remoteOptions array where the existing options from the last SQL query are stored and then call mergeRemoteOptions().

For example, the following code adds a new option to the "selectService" radio button while preserving the list of options set by the last SQL Query:

getFieldById("selectService").model.attributes.remoteOptions.push( {value: "redecorating", label: "Redecorating"} );
var aOptions = getFieldById("selectService").model.attributes.remoteOptions;
getFieldById("selectService").model.mergeRemoteOptions(aOptions);

If the SQL query for the field is reexecuted because it contains a dependent field whose value has been changed by the user, then it will overwrite the list of options in the model.attributes.remoteOptions array. The way to get around this problem is to add the new option to model.attributes.localOptions, which is an array of the fixed options that were set by the **options** property of the dropdown, suggest, checkgroup or radio. Changing the localOptions array will not cause the list of options to be updated on the screen, so mergeRemoteOptions() needs to be called afterwards to display the changed list of options to the user.

For example:

getFieldById("selectService").model.attributes.localOptions.push( {value: "lawn", label: "Lawn Service"} );
var aOptions = getFieldById("selectService").model.attributes.remoteOptions;
getFieldById("selectService").model.mergeRemoteOptions(aOptions);

Deleting an option from the localOptions or remoteOptions array is a bit more difficult. If the order of the options is known, then the Array.splice() method can be used to remove an option.

For example, the following code removes the third option in the "selectService" field and then displays the changed list of options:

getFieldById("selectService").model.attributes.localOptions.splice(2, 1);
getFieldById("radio-id").model.mergeRemoteOptions([]);

Note that arrays start counting from 0, so 2 is the third option in the array.

If the order of the options is not known, then the code will have to search through the array for the option to remove and then call .splice(). For example, the following code deletes an option whose value is "lawn":

var opts = getFieldById("selectService").model.attributes.localOptions;
for (var i = 0; i < opts.length; i++) {
   if (opts[i].value == "lawn") {
       getFieldById("selectService").model.attributes.localOptions.splice(i, 1);
   }
}
getFieldById("selectService").model.mergeRemoteOptions([]);

The problem with using JavaScript to add and remove options from a list is that if the Dynaform is redisplayed, the original list of options will be used. If the field is set to an option which is isn't in the original list of options, then field will be displayed as blank. JavaScript needs to be added that will recreate the list of options as it existed the last time the Dynaform was displayed. For this reason, it is recommended to use SQL queries with dependent fields to create the list of available options, because it is reproducible if the Dynaform is opened a second time.


Understanding how mergeRemoteOptions() works

When the getFieldById("field-id").model.mergeRemoteOptions() function is executed, it first overwrites the list of options from the last SQL query, stored in getFieldById("field-id").model.attributes.remoteOptions.

Then, it concatenates the .remoteOptions array to the end of the .localOptions array and writes that to:
getFieldById("field-id").model.attributes.options

Finally, it takes the complete list in the .options array and displays that in the list of options for the field, so that it is visible to the user.