JavaScript Customizations for Collections

Note: This page applies primarily to the classic form designer.

Collections group together related sets of fields on a form, making it easy to repeat those sets. Addresses are a very common kind of collection, as they normally consist of several fields that always go together. In this section, we explain how you can determine the selectors you need for customizations on collections, and provide examples of some common customizations.

Selectors

The region taken up by the entire collection is a li element with a name and id in the format qN (q67 in the example below). The class of this element is cf-collection-block, which distinguishes the collection from other field types. The following screenshot shows the area occupied by a collection with two fields that are repeated. The li element representing the element is highlighted in blue in the right pane.

The HTML element corresponding to a collection.

Within the li element that comprises the entire collection, we have the following elements:

  • The collection title: A div element with the class cf-section-header.
  • Another div element with the classes cf-collection and kx-repeatable. This is the element that contains the sets of fields.

We will focus on how to select elements within the latter element. Within this element, we have div elements of class form-q. Each of these represents a set of fields—in our example, a pair of fields "Apples and Oranges" and "Just Apples". Our example has two sets in the collection, so there are two div elements with class form-q.

The HTML element corresponding to a set of fields in a collection.

Now we expand these class form-q elements to examine their inner structure. Both fields are contained in an unordered list element (ul) with the class rpx. Each field is represented by a li element with one part corresponding to the field label container and another to the input box container. The structure of each field is the same as that of conventional fields. Each field is wrapped in a field container with an ID of the format qN. In a collection with repeating sets of fields, this ID will not be unique—for example, all "Just Apples" field containers in our collection will have the same id, q72.

The HTML element corresponding to an individual field in a set of fields, within a collection.

For fields in collections, input boxes also have different ID assignment rules compared to conventional fields. To aid users in determining the patterns of these IDs, we have labeled each input box in our sample collection with its corresponding id:

Sample collection with each field labelled with its ID.

The format for fields in collections with repeating sets is FieldN(setNumber). With each additional set, the FieldN prefixes stay the same, but the setNumbers increment by one.

Reusing Inputs for Repeating Sets

When you have repeating sets of fields in a collection, you may want certain fields in later sets to be automatically filled with the values of their counterparts in previous sets. The following animation shows the desired behavior, as applied to the "Just Apples" field in the collection:

The following JavaScript snippet implements this customization.

$(document).ready(function() {
  $('a[ref-id="q20"]').click(function() { //after "Add" button is clicked
    var setCount = $(".cf-collection-block .rpx").length; //count number of repeating sets
    var newfieldid = "Field72(" + setCount + ")"; //id of "Just Apples" field that was just added
    var oldfieldid = "Field72(" + (setCount-1) + ")"; //id of previous "just Apples" field
    //set value of new field to value of previous field
    $('input[id="' + newfieldid + '"]').val($('input[id="' + oldfieldid + '"]').val());
  });
});

When the document is loaded, the browser waits for a click on the "Add" button, which has the attribute ref-id equal to q20.

The HTML element corresponding to the "Add" button in a collection with a dynamic number of sets.

After the click occurs, the following operations take place:

  • The number of sets in the collection is counted. If you had started with one collection and clicked "Add", this number will now be 2. The count works by looking in the collection block, which is identified by its class cf-collection-block, and counting the number of elements with class rpx in this block. This works because each set is contained within a ul element with class rpx, and there are no other elements in the collection block that have that class. If you have multiple collections on the same page, you should alter this code to use a hierarchical selector with the collection's id rather than its class. Otherwise, setCount will be the total number of sets on the page, counted across all collections on the page.
  • The variable newfieldid is constructed to represent the id of the newly added field that we want to copy a value over to. In this example, we want to copy the old value of "Just Apples" over to the newly added instance of "Just Apples". The format of all "Just Apples" fields in this collection is Field72(setNumber). The value of setNumber for the newly added field will just be the number of sets, i.e. setCount.

The HTML element corresponding to the field in a collection whose value should be copied to the same field in later sets.

  • The variable oldfieldid is constructed to represent the id of the instance of "Just Apples" preceding the most recently added instance. This will have the format Field72(setCount-1).
  • Using newfieldid and oldfieldid, we set the latest instance of "Just Apples" to have the same value as its preceding instance.

Reusing Inputs Conditional on a Checkbox

Sometimes, you may want the automatic filling in the previous example to occur only when a box is checked. This is common, for instance, in online transactions where one has to specify a billing address and a shipping address. To save users time, you can have them check a box to indicate that the second address is the same as the first address. The collection corresponding to the second address will then be automatically filled with the values from the first collection.

The desired behavior is something like the following:

The JavaScript we used to implement this is as follows. It assumes that the Billing Address collection has been assigned the custom class billing, the Shipping Address has been assigned the custom class shipping, and the checkbox has been assigned the class sameAddress.

$(document).ready(function () { 
  $('.sameAddress').change(function() { //checks for changes in the checkbox
    if ($(this).find('input[value="Yes"]').is(':checked')) {
      //make list of all inputs in Shipping Address collection
      var shippingAddress = $('.shipping').find('input');
      //make list of all inputs in Billing Address collection 
      var billingAddress = $('.billing').find('input');
      //make list of all dropdown choices in Shipping Address collection
      var shippingDropdowns = $('.shipping').find('select');
      //make list of all dropdown choices in Billing Address collection
      var billingDropdowns = $('.billing').find('select');
      for (i=0; i<3; i++) { //iterate over the max. number of fields for each field type
        $(shippingAddress[i]).val($(billingAddress[i]).val()); //copy text inputs
        $(shippingDropdowns[i]).val($(billingDropdowns[i]).val()); //copy dropdown choices
      }
    }
  });
});

The code works as follows. When the document is loaded, the browser waits for changes made to the checkbox that indicates whether the shipping address is the same as the billing address. When a change occurs, the browser does the following if the checkbox is selected:

  • Make a list of all inputs in the Shipping Address collection
  • Make a list of all inputs in the Billing Address collection
  • Do the same two actions, but for drop-down menus instead
  • Copy the values from the Billing Address collection over to the Shipping address collection.

In this particular example, the duplication operation is slightly more complicated because we have both text inputs and drop-down menus in the address collections. Text input elements are of the type input, while drop-down menus are of the type select, so we made separate lists for each type. If you use the default address collection provided in the form designer's Layout page, you can eliminate the additional lines that handle the drop-down fields.

Targeting the Same Fields in Every Set

In some situations, two fields in a set may be systematically related, such that every set added to that collection should obey that relationship. To enforce this, you may want to carry out the same JavaScript operation in every set within a repeating collection. In the following example, we have repeating sets where we want "Not Applicable" to be filled in whenever "No" is selected in the previous field.

Our desired behavior is shown in the following animation:

We implement this using the following JavaScript snippet. The code assumes that you have assigned the custom class reportInfo to the collection and that the id of the "Reviewer" field is q58.

$(document).ready(function () {
  $('.reportInfo').on('change', '[type="radio"]', reqChange);


  function reqChange() {
    $('.reportInfo .rpx .radio-checkbox-fieldset').each(function () {
      $(this).find('input:checked').each(function() {
        if ($(this).val() == "No") {
          var reviewerField = $(this).closest('.rpx').find('[name="q58"]');
          $(reviewerField).find('input').val('Not Applicable');
        }
      })
    })
  }
})

When the document has loaded, the browser waits for a change in the radio buttons in the collection. When a change happens, the function reqChange is called. This function loops through every set of Yes/No radio buttons ($('.reportInfo .rpx .radio-checkbox.fieldset') selects for these sets) and does the following:

  • It finds all radio buttons that are selected, using .find('input:checked').
  • Within these buttons, it searches for those that have the value "No".
  • For the selected buttons with the value "No", it searches its ancestors for the closest element with class rpx. This element is the container for a set of fields. Within the container, it then searches for the Reviewer field, which is identified in our example by having a name attribute of q58.
  • Within the Reviewer field, the function looks for the input element and sets its value to "Not Applicable."