Use field dependencies in JSON Forms

A field dependency links one form field’s value to the API request of another field. When the source field changes, the dependent field automatically re-fetches its options using the new value as a parameter. This lets you build forms where one selection meaningfully constrains or filters what the next field shows.

A common pattern is a cascading dropdown: a first dropdown selects an entity such as a device, and a second dropdown automatically populates with data specific to that entity such as that device’s interfaces. Another pattern is a constrained search: a number input controls a maxResults parameter, so the form operator directly determines how many results a dropdown retrieves.

Without field dependencies, you would need a separate form submission and page reload to achieve the same effect—or hardcode parameters that the form operator can never change.

Field dependencies are configured on the dependent field’s dynamic dropdown, under Variables (Field Dependency). The source field is referenced by its JSON schema path (for example, /device). When using GET requests, the dependency replaces a route parameter. When using POST requests, it replaces a property in the request body.

The following examples demonstrate both patterns.

Example 1: Retrieve device interfaces (GET request)

A Device dropdown populates from Configuration Manager. Selecting a device causes an Interface dropdown to fetch and display only that device’s interfaces (GET request with a route parameter dependency).

Step 1: Build the form structure

1

Create a JSON Form

In JSON Forms, create a new form.

2

Add two dropdown elements

Drag two Dropdown elements onto the canvas.

3

Label the dropdowns

Hover over the menu on each dropdown and click the gear icon. In the Configure dialog, set the Label of the first dropdown to Device and the second to Interface.

Form with Device and Interface dropdown elements labeled
4

Save

Click Save.

Step 2: Configure dynamic data binding for the Device dropdown

1

Open Configure

Hover over the Device dropdown and click the gear icon.

2

Add dynamic data binding

Click + Options and select Dynamic. The Dynamic Data Binding editor opens.

3

Set the request configuration

Enter the following under Request Configuration:

Method: POST
Base URL: /configuration_manager
API Route: /devices
4

Set the request body

Enter the following in the Request Body editor:

1{
2 "options": {
3 "limit": 10000,
4 "start": 0,
5 "sort": [
6 {
7 "name": 1,
8 "address": -1,
9 "port": 1
10 }
11 ]
12 }
13}
5

Generate the response body

Click Make API Call.

Make API Call generating the response body for device data
6

Configure data mapping

Under Data Mapping, select Source-To-Target and enter:

Source Property: /list
Property Key: /name

Click Query Data to preview the list of discoverable devices.

Data Mapping preview showing discoverable devices
7

Save

Click Back, then click Save.

Step 3: Configure field dependencies for the Interface dropdown

1

Set the request configuration

Enter the following under Request Configuration:

Method: GET
Base URL: /configuration_manager
API Route: /devices/:name/configuration
2

Set the device name parameter

In the Define Parameters name field, enter an active device name from Configuration Manager.

3

Generate the device configuration

Click Make API Call to retrieve the device configuration in the Response Body.

4

Configure data mapping

Under Data Mapping, select JSON Transformation and enter the “Transform Device Config” JST file provided below. Click Run Transformation. The Target Data Preview displays the interface name.

5

Set the field dependency

Under Variables (Field Dependency), select Form Reference and enter the Device field reference:

/device
Request configuration and field dependency settings for the Interface dropdown
6

Save

Click Back, then click Save.

Step 4: Validate the form

1

Open the form

Go to Studio > JSON Forms, expand the JSON Forms menu in the left nav, and select the form.

2

Preview the form

Click the eye icon to open Preview Form. Select a device from the Device dropdown. The Interface dropdown populates with interfaces from that device’s configuration.

3

Inspect the schema

Click Show Form Data to display the JSON schema. Click Close to return to the preview.

Preview Form showing device and interface selections

Data in Preview Form comes from a live device and may take a few seconds to appear depending on device configuration size and network conditions.

JSON transformation file for device config

Copy the JSON below into a .txt file and save it as Transform Device Config.jst.json. Then import the file into your transformation library in Studio.

1{
2 "name": "Transform Device Config",
3 "incoming": [
4 {
5 "$id": "config",
6 "type": "string"
7 }
8 ],
9 "outgoing": [
10 {
11 "$id": "out",
12 "type": "array"
13 }
14 ],
15 "steps": [
16 {
17 "id": 2,
18 "type": "assign",
19 "from": {
20 "location": "incoming",
21 "name": "config",
22 "ptr": ""
23 },
24 "to": {
25 "location": "method",
26 "name": 1,
27 "ptr": "/args/0/value"
28 },
29 "context": "#"
30 },
31 {
32 "id": 1,
33 "type": "method",
34 "library": "String",
35 "method": "split",
36 "args": [
37 null,
38 "\n",
39 null
40 ],
41 "view": {
42 "row": 1,
43 "col": 1
44 },
45 "context": "#"
46 },
47 {
48 "id": 4,
49 "type": "assign",
50 "from": {
51 "location": "method",
52 "name": 1,
53 "ptr": "/return"
54 },
55 "to": {
56 "location": "method",
57 "name": 3,
58 "ptr": "/args/0/value"
59 },
60 "context": "#"
61 },
62 {
63 "id": 3,
64 "type": "method",
65 "library": "Array",
66 "method": "filter",
67 "args": [
68 null,
69 "ƒ_query_1"
70 ],
71 "view": {
72 "row": 2,
73 "col": 2
74 },
75 "context": "#"
76 },
77 {
78 "id": 6,
79 "type": "method",
80 "library": "Array",
81 "method": "map",
82 "args": [
83 null,
84 "ƒ_map_1"
85 ],
86 "view": {
87 "row": 1,
88 "col": 3
89 },
90 "context": "#"
91 },
92 {
93 "id": 7,
94 "type": "assign",
95 "from": {
96 "location": "method",
97 "name": 3,
98 "ptr": "/return"
99 },
100 "to": {
101 "location": "method",
102 "name": 6,
103 "ptr": "/args/0/value"
104 },
105 "context": "#"
106 },
107 {
108 "id": 8,
109 "type": "assign",
110 "from": {
111 "location": "method",
112 "name": 6,
113 "ptr": "/return"
114 },
115 "to": {
116 "location": "outgoing",
117 "name": "out",
118 "ptr": ""
119 },
120 "context": "#"
121 }
122 ],
123 "functions": [
124 {
125 "name": "ƒ_query_1",
126 "incoming": [
127 { "$id": "element", "type": ["array","boolean","number","integer","string","object","null"] },
128 { "title": "index", "type": "number", "optional": true, "$id": "index" },
129 { "type": "array", "$id": "array", "optional": true },
130 { "$id": "thisArg", "type": "object", "properties": {}, "isContext": true, "isThis": true, "isIndexed": true }
131 ],
132 "outgoing": [
133 { "title": "return", "type": "boolean", "$id": "return" }
134 ],
135 "steps": [
136 { "id": 5, "type": "assign", "from": { "location": "incoming", "name": "element", "ptr": "" }, "to": { "location": "method", "name": 4, "ptr": "/args/0/value" }, "context": "#" },
137 { "id": 4, "type": "method", "library": "String", "method": "trim", "args": [null], "view": { "row": 2, "col": 1 }, "context": "#" },
138 { "id": 6, "type": "assign", "from": { "location": "method", "name": 4, "ptr": "/return" }, "to": { "location": "method", "name": 1, "ptr": "/args/0/value" }, "context": "#" },
139 { "id": 1, "type": "method", "library": "String", "method": "startsWith", "args": [null, "interface", null], "view": { "row": 1, "col": 1 }, "context": "#" },
140 { "id": 3, "type": "assign", "from": { "location": "method", "name": 1, "ptr": "/return" }, "to": { "location": "outgoing", "name": "return", "ptr": "" }, "context": "#" }
141 ],
142 "functions": [],
143 "view": { "col": 1, "row": 3 },
144 "id": "ƒ_query_1",
145 "comments": []
146 },
147 {
148 "name": "ƒ_map_1",
149 "incoming": [
150 { "$id": "currentValue", "type": ["array","boolean","number","integer","string","object","null"] },
151 { "title": "index", "type": "number", "optional": true, "$id": "index" },
152 { "type": "array", "$id": "array", "optional": true },
153 { "$id": "thisArg", "type": "object", "properties": {}, "isContext": true, "isThis": true, "isIndexed": true }
154 ],
155 "outgoing": [
156 { "title": "newValue", "type": ["array","boolean","number","integer","string","object","null"], "editable": true, "$id": "newValue" }
157 ],
158 "steps": [
159 { "id": 1, "type": "method", "library": "String", "method": "trim", "args": [null], "view": { "row": 1, "col": 1 }, "context": "#" },
160 { "id": 2, "type": "assign", "from": { "location": "incoming", "name": "currentValue", "ptr": "" }, "to": { "location": "method", "name": 1, "ptr": "/args/0/value" }, "context": "#" },
161 { "id": 3, "type": "assign", "from": { "location": "method", "name": 1, "ptr": "/return" }, "to": { "location": "outgoing", "name": "newValue", "ptr": "" }, "context": "#" }
162 ],
163 "functions": [],
164 "view": { "col": 1, "row": 3 },
165 "id": "ƒ_map_1",
166 "comments": []
167 }
168 ],
169 "view": { "col": 3, "row": 5 },
170 "_id": "6472c5cb363dd75d098b8d0d",
171 "description": "",
172 "comments": [],
173 "version": "3.23.3-2022.1.14"
174}

Example 2: Limit a form search (POST request)

A Form Limit number input controls the maxResults parameter of a Forms dropdown search (POST request with a request body dependency).

A Forms dropdown makes a POST request to /formbuilder/forms/search. The request body property /options/maxResults limits how many forms are returned. A Form Limit number input is added to the form and set as the field dependency for /options/maxResults, so the form operator controls the result cap directly.

Step 1: Build the form structure

1

Add elements

Drag a number input and a dropdown onto a new form.

2

Label the number input

Hover over the number input and click the gear icon. Set the Label to Form Limit and click Save.

3

Label the dropdown

Open the dropdown’s Configure dialog and set the Label to Forms. Leave the dialog open for the next step.

Form with Form Limit number input and Forms dropdown

Step 2: Configure dynamic data binding for the Forms dropdown

1

Add dynamic data binding

Click + Options and select Dynamic. The Dynamic Data Binding options appear.

2

Set the request configuration

Enter the following under Request Configuration:

Method: POST
Base URL: /formbuilder
API Route: /forms/search
3

Set the request body

Enter the following in the Request Body:

1{
2 "options": {
3 "maxResults": 25,
4 "startAt": 0,
5 "sort": { "name": 1 },
6 "fields": ["name","children","elements","createdBy","created","lastUpdatedBy","lastUpdated","tags"],
7 "filter": { "name": { "$regex": "(e)", "$options": "i" } },
8 "expand": ["createdBy","lastUpdatedBy"]
9 }
10}
4

Generate the response body

Click Make API Call. A list of forms appears in the Response Body.

Forms dropdown dynamic data binding settings
5

Configure data mapping

Under Data Mapping, click Source-To-Target and enter:

Source Property: /results
Property Key: /name

Click Query Data to preview the form names.

Data Mapping settings for the Forms dropdown
6

Set the field dependency

Under Variables (Field Dependency), click + Variable and enter:

Request Body Pointer: /options/maxResults
Schema Reference: /formLimit

Click Back, then click Save.

Field Dependency settings linking Form Limit to maxResults

Step 3: Test the form

1

Preview the form

Click the eye icon to open a live preview.

2

Verify behavior

Confirm that changing the Form Limit value caps the number of options in the Forms dropdown.

API calls and dynamic data binding

Adapter calls do not always map directly to the underlying system-level API call. This mainly affects system-level GET calls.

GET calls translated to POST

All system-level GET calls with defined query parameters in the adapter’s OpenAPI/Swagger specification are translated to adapter POST calls.

For example, consider the F5 BIG-IP API:

F5 BIG-IP adapter showing a system-level GET call translated to an adapter POST call

At the system level this is a GET call, but as an adapter call it must be a POST request with the listed object keys in the request body. Without those parameters, the adapter call returns no output. The keys can be provided as empty strings:

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

Find required parameters

For system-level GET calls that must be translated to POST, find the required parameters at:

https://<IAP_IP>:<PORT>/rest-api

If an adapter GET call is not listed there, confirm that:

  • An adapter POST call for that system does not already exist.
  • The developer has authorization to make the adapter call.