Using Dynamic Dependency in JSON Forms
  • 27 Feb 2025
  • Dark
    Light
  • PDF

Using Dynamic Dependency in JSON Forms

  • Dark
    Light
  • PDF

Article summary

The following examples demonstrate how field dependencies can improve the dynamism and adaptability of your JSON forms.

  • The first populates a dropdown menu with all available Configuration Manager devices. Once a device is selected via this dropdown, its interfaces are made accessible via a second dropdown.
  • The second limits the number of forms returned by a search based on the value of a number input.
Note:

See JSON Forms for details on creating JSON Forms and working with Form Builder to create the form elements referenced throughout this guide.

Example 1 — Retrieving Device Interfaces (GET Request)

Follow these steps to build and configure dynamic dependencies in the JSON form. As the form is built, it can be previewed and the generated form schemas can be inspected.

Step 1: Build JSON Form Structure

First, create the structure of the JSON form:

  1. Create a JSON Form using the Automation Studio application.

  2. Add two dropdown elements to the JSON form canvas using the Form Elements bin.

  3. Hover over the menu button () at the far-right of each dropdown element and click the grid icon that appears. The Configure dialog opens.

  4. Use the Label field to name the first dropdown element "Device" and the second "Interface" (Figure 1).

    Figure 1
    Figure 1

  5. Click Save () to retain the naming inputs.

Step 2: Add Dynamic Data Binding to the Device Dropdown

Next, add the logic that is required to dynamically populate the fields. This is done via API calls.

  1. Hover over the menu button () and click the gear icon () to open the Configure dialog.

  2. Click the +Options button located at the bottom of the dialog and select the Dynamic configuration type. The Dynamic Data Binding editor displays.

  3. For the Request Configuration, use the following parameters:

    Method:  POST
    Base URL:  /configuration_manager
    API Route: /devices
    
  4. In the Request Body editor, add options to help sort the list as well as limit the amount of data that is pulled. At a minimum, the suggested options are:

    {
      "options": {
        "limit": 10000,
        "start": 0,
        "sort": [
          {
            "name": 1,
            "address": -1,
            "port": 1
          }
        ]
      }
    }
    
  5. Once the Request Body is added, click the Make API Call button to generate the Response Body (Figure 2).

    Figure 2
    Figure 2

  6. For Data Mapping, use Source-To-Target and the field inputs below.

    Source Property: /list
    Property Key: /name
    
  7. Click the Query Data button. The Data Mapping properties will generate a preview list of devices that are available and discoverable by Configuration Manager (Figure 3).

    Figure 3
    Figure 3

  8. Click the Back button once all configurations are set and then click Save to retain all changes.

Step 3: Configure the Interface Dropdown's Field Dependencies

Once the "Device" selections are set, you can then configure the dynamic options for "Interfaces".

  1. For the Request Configuration, use the following:

    Method:  GET
    Base URL:  /configuration_manager
    API Route: /devices/:name/configuration
    
  2. Populate the Define Parameters name field with an active device name found within Configuration Manager.

  3. Click the Make API Call button to return the device configuration (Response Body).

  4. For Data Mapping, select JSON Transformation and input the "Transform Device Config" JST file provided at the end of this guide.

  5. Click the Run Transformation button. The Target Data Preview editor displays the interface name.

  6. For the Variables (Field Dependency), select Form Reference and input the Device field configured in the previous section.

    /device
    

    Figure 4
    Figure 4

  7. Click the Back button once all interface mappings are set and then click Save to retain all configuration changes.

Step 4: Validate the JSON Form

To test the logic of the JSON form:

  1. Navigate to Itential Platform → Automation Studio → JSON Forms. JSON Forms is listed in the left navbar as its own subcategory in Automation Studio.
  2. Expand the JSON Forms menu in the left navbar and select the JSON Form.
  3. Click the eye icon at the top to open the Preview Form dialog.
  4. Select a device from the Device dropdown. Likewise, select the interface captured from the device configuration in the Interface dropdown.
  5. Click Show Form Data to display the JSON schema. Click Close to return to the preview modal.

Figure 5
Figure 5

Note:

The information presented within Preview Form is from a live device and may take a few seconds to display based on the size of the device configuration as well as network congestion.

JSON Transformation File for Device Config

To import, copy the JSON into a .txt file and save it as “Transform Device Config.jst.json”. Then import the file into your transformation library under Automation Studio.

{
  "name": "Transform Device Config",
  "incoming": [
    {
      "$id": "config",
      "type": "string"
    }
  ],
  "outgoing": [
    {
      "$id": "out",
      "type": "array"
    }
  ],
  "steps": [
    {
      "id": 2,
      "type": "assign",
      "from": {
        "location": "incoming",
        "name": "config",
        "ptr": ""
      },
      "to": {
        "location": "method",
        "name": 1,
        "ptr": "/args/0/value"
      },
      "context": "#"
    },
    {
      "id": 1,
      "type": "method",
      "library": "String",
      "method": "split",
      "args": [
        null,
        "\n",
        null
      ],
      "view": {
        "row": 1,
        "col": 1
      },
      "context": "#"
    },
    {
      "id": 4,
      "type": "assign",
      "from": {
        "location": "method",
        "name": 1,
        "ptr": "/return"
      },
      "to": {
        "location": "method",
        "name": 3,
        "ptr": "/args/0/value"
      },
      "context": "#"
    },
    {
      "id": 3,
      "type": "method",
      "library": "Array",
      "method": "filter",
      "args": [
        null,
        "ƒ_query_1"
      ],
      "view": {
        "row": 2,
        "col": 2
      },
      "context": "#"
    },
    {
      "id": 6,
      "type": "method",
      "library": "Array",
      "method": "map",
      "args": [
        null,
        "ƒ_map_1"
      ],
      "view": {
        "row": 1,
        "col": 3
      },
      "context": "#"
    },
    {
      "id": 7,
      "type": "assign",
      "from": {
        "location": "method",
        "name": 3,
        "ptr": "/return"
      },
      "to": {
        "location": "method",
        "name": 6,
        "ptr": "/args/0/value"
      },
      "context": "#"
    },
    {
      "id": 8,
      "type": "assign",
      "from": {
        "location": "method",
        "name": 6,
        "ptr": "/return"
      },
      "to": {
        "location": "outgoing",
        "name": "out",
        "ptr": ""
      },
      "context": "#"
    }
  ],
  "functions": [
    {
      "name": "ƒ_query_1",
      "incoming": [
        {
          "type": [
            "array",
            "boolean",
            "number",
            "integer",
            "string",
            "object",
            "null"
          ],
          "$id": "element"
        },
        {
          "title": "index",
          "type": "number",
          "optional": true,
          "$id": "index"
        },
        {
          "type": "array",
          "$id": "array",
          "optional": true
        },
        {
          "$id": "thisArg",
          "type": "object",
          "properties": {},
          "isContext": true,
          "isThis": true,
          "isIndexed": true
        }
      ],
      "outgoing": [
        {
          "title": "return",
          "type": "boolean",
          "$id": "return"
        }
      ],
      "steps": [
        {
          "id": 5,
          "type": "assign",
          "from": {
            "location": "incoming",
            "name": "element",
            "ptr": ""
          },
          "to": {
            "location": "method",
            "name": 4,
            "ptr": "/args/0/value"
          },
          "context": "#"
        },
        {
          "id": 4,
          "type": "method",
          "library": "String",
          "method": "trim",
          "args": [
            null
          ],
          "view": {
            "row": 2,
            "col": 1
          },
          "context": "#"
        },
        {
          "id": 6,
          "type": "assign",
          "from": {
            "location": "method",
            "name": 4,
            "ptr": "/return"
          },
          "to": {
            "location": "method",
            "name": 1,
            "ptr": "/args/0/value"
          },
          "context": "#"
        },
        {
          "id": 1,
          "type": "method",
          "library": "String",
          "method": "startsWith",
          "args": [
            null,
            "interface",
            null
          ],
          "view": {
            "row": 1,
            "col": 1
          },
          "context": "#"
        },
        {
          "id": 3,
          "type": "assign",
          "from": {
            "location": "method",
            "name": 1,
            "ptr": "/return"
          },
          "to": {
            "location": "outgoing",
            "name": "return",
            "ptr": ""
          },
          "context": "#"
        }
      ],
      "functions": [],
      "view": {
        "col": 1,
        "row": 3
      },
      "id": "ƒ_query_1",
      "comments": []
    },
    {
      "name": "ƒ_map_1",
      "incoming": [
        {
          "type": [
            "array",
            "boolean",
            "number",
            "integer",
            "string",
            "object",
            "null"
          ],
          "$id": "currentValue"
        },
        {
          "title": "index",
          "type": "number",
          "optional": true,
          "$id": "index"
        },
        {
          "type": "array",
          "$id": "array",
          "optional": true
        },
        {
          "$id": "thisArg",
          "type": "object",
          "properties": {},
          "isContext": true,
          "isThis": true,
          "isIndexed": true
        }
      ],
      "outgoing": [
        {
          "title": "newValue",
          "type": [
            "array",
            "boolean",
            "number",
            "integer",
            "string",
            "object",
            "null"
          ],
          "editable": true,
          "$id": "newValue"
        }
      ],
      "steps": [
        {
          "id": 1,
          "type": "method",
          "library": "String",
          "method": "trim",
          "args": [
            null
          ],
          "view": {
            "row": 1,
            "col": 1
          },
          "context": "#"
        },
        {
          "id": 2,
          "type": "assign",
          "from": {
            "location": "incoming",
            "name": "currentValue",
            "ptr": ""
          },
          "to": {
            "location": "method",
            "name": 1,
            "ptr": "/args/0/value"
          },
          "context": "#"
        },
        {
          "id": 3,
          "type": "assign",
          "from": {
            "location": "method",
            "name": 1,
            "ptr": "/return"
          },
          "to": {
            "location": "outgoing",
            "name": "newValue",
            "ptr": ""
          },
          "context": "#"
        }
      ],
      "functions": [],
      "view": {
        "col": 1,
        "row": 3
      },
      "id": "ƒ_map_1",
      "comments": []
    }
  ],
  "view": {
    "col": 3,
    "row": 5
  },
  "_id": "6472c5cb363dd75d098b8d0d",
  "description": "",
  "comments": [],
  "version": "3.23.3-2022.1.14"
}

Example 2 — Limiting a Form Search (POST Request)

In this example, a dynamic dropdown named Forms makes a POST request to Itential Platform's /formbuilder/forms/search endpoint. This populates the dropdown with a list of forms that meet the criteria specified in the request body (for more information, see Itential's API documentation). One property of the request body, /options/maxResults, is responsible for limiting the number of forms returned by the request. In practical terms, this means it also limits how many forms are displayed by the dropdown.

We would like to allow the form operator to dictate this limit; as such, we will also create a number input named Form Limit. In our dropdown configuration, we will turn /options/maxResults into a field dependency, sourcing its value from the Form Limit input.

ⓘ Note — Version Differences:

Field dependencies were made compatible with POST requests in the Platform 6 version of Itential Platform. In prior versions, they could only be used with GET requests.

Step 1: Build JSON Form Structure

First, we must create a skeleton form. We'll build it out in the later steps. To begin:

  1. Drag and drop a number input and a dropdown onto a fresh JSON form. As elements are placed, the form will begin to resemble a table, with each element comprising a separate row.
  2. Hover over the more options (horizontal ellipsis) icon at the end of the number input's row. A gear icon will display; click it to open the Configure modal.
  3. Edit the number input's Label to read "Form Limit." Then, click the Save button located at the bottom of the modal.
  4. Open the dropdown's Configure modal and edit its Label to read "Forms."

Do not close the dropdown's Configure modal; we will be making further configuration changes in the next section.

Figure 6: Skeleton Form
A screenshot of the skeleton form.

Step 2: Add Dynamic Data Binding to the Forms Dropdown

Next, we must set up dynamic data binding for the Forms dropdown.

  1. Click the + Options button at the bottom-right corner of the modal. The Configure: Options modal will appear.

  2. Under the Type header, click the Dynamic radio button. The dropdown's Dynamic Data Binding options will display.

  3. Set the Request Configuration as follows:

    Method:  POST
    Base URL:  /formbuilder
    API Route: /forms/search
    
  4. Set the Request Body as follows:

    { 
      "options": {
        "maxResults": 25,
        "startAt": 0,
        "sort": {
          "name": 1
        },
        "fields": [
          "name",
          "children",
          "elements",
          "createdBy",
          "created",
          "lastUpdatedBy",
          "lastUpdated",
          "tags"
        ],
        "filter": {
          "name": {
            "$regex": "(e)",
            "$options": "i"
          }
        },
        "expand": [
          "createdBy",
          "lastUpdatedBy"
        ]
      }
    }
    
  5. Click the Make API Call button to populate the Response Body. In this scenario, you should see a list of forms.

    Figure 7: Dynamic Data Binding
    A screenshot of the Forms dropdown's dynamic data binding settings.

  6. Under the Data Mapping header, click the Source-To-Target option.

  7. Examine the response body. Note that every top-level object in the results array contains a name key corresponding to a different form. We would like to display these keys in the dropdown. To do so, set the Source Property and the Property Key fields as follows:

    Source Property: /results
    Property Key: /name
    
  8. Click the Query Data button. A preview of the data that will be displayed by the dropdown appears; in this scenario, you should see a list of form names.

    Figure 8: Data Mapping Settings
    A screenshot of the Forms dropdown's data mapping settings.

  9. Under the Variables (Field Dependency) header, click the + Variable button. Two fields will appear: the Request Body Pointer and the Schema Reference.

  10. We would like to parameterize the request body's /options/maxResults property, replacing its value with that of the Form Limit number input. To do so, configure the fields as follows:

    Request Body Pointer: /options/maxResults
    Schema Reference:  /formLimit
    
  11. When you are finished, click the Back button to return to the Configure modal. Then, click the Save button to save your changes and exit the modal.

    Figure 9: Field Dependency Settings
    A screenshot of the Forms dropdown's field dependency settings.

Step 3: Test Form Behavior

All that's left is to confirm that the form is functioning as intended:

  1. Click the Preview JSON Form (eye icon) button located near the upper-right corner of the form builder. A functional preview of your form will be displayed.
  2. Confirm that the Form Limit number input effectively caps the Forms dropdown's options.

Working with API Calls in JSON Forms with Dynamic Data Binding

When working with Dynamic Data Binding in JSON Forms, it is important to know the adapter calls do not always translate directly to the system-level API call the adapter is translating. This mainly applies to system-level GET calls.

GET/POST API Calls

As a criterion, all system-level GET calls with defined query parameters (optional or mandatory) in the adapter's OpenAPI/Swagger specification document will be treated (translated) as adapter POST calls.

To illustrate, let's refer to the F5 BIG-IP API depicted in the figure below.

Figure 10: Retrieve BIG-IP Devices
F5 BIG-IQ Adapter

At the system-level, this is a GET API call. However, in order to make it an adapter call, the API has to be a POST request that requires an object with the object keys listed. Without those parameters in the request body, the adapter call will not work nor provide any output. In this instance, the object keys can be provided as empty values:

{ "select":"", "filter":""}

Use OpenAPI Help to Access Parameters

For all system-level GET calls that need to be translated to POST calls, the required parameters that need to be provided can be found through:

https://IAP_IP-LINK_Address:PORT/rest-api

If an adapter GET call is not listed, two items need to be reviewed:

  • Validate that an adapter POST call associated with the system does not exist.

  • Validate the developer building the JSON form has authorization to make the adapter call that is being attempted.

Related Reading


Was this article helpful?

Changing your password will log you out immediately. Use the new password to log back in.
First name must have atleast 2 characters. Numbers and special characters are not allowed.
Last name must have atleast 1 characters. Numbers and special characters are not allowed.
Enter a valid email
Enter a valid password
Your profile has been successfully updated.