Portal Community

How $json Works

// 1. Fetch entity data from API
const applicant = await api.get('/applicants/42');
// {
//   firstName: 'Jane',
//   lastName:  'Smith',
//   address: {
//     city:    'London',
//     country: 'GB'
//   }
// }

// 2. Pass to the form as initialValues
<FormRenderer
  schema={schema}
  initialValues={applicant}    // ← becomes the $json source
  mode="edit"
  onSubmit={handleSubmit}
/>

// 3. Controls bind to paths within initialValues
// { "id": "first-name", "binding": { "source": "$json", "path": "firstName" } }
// → initial value: 'Jane'

// { "id": "city", "binding": { "source": "$json", "path": "address.city" } }
// → initial value: 'London'

Writing Back

// When the user changes 'city' from 'London' to 'Manchester':
// engine.setValue('city', 'Manchester')

// engine.getValues() now returns:
// {
//   'first-name': 'Jane',
//   'city':       'Manchester',
//   ...
// }

// Your submit handler persists this:
const handleSubmit = async (values: Record<string, any>) => {
  await api.put('/applicants/42', {
    firstName:       values['first-name'],
    'address.city':  values['city'],
    // ...
  });
};

Nested Object Example

// Form schema — binding to nested paths
{
  "controls": [
    {
      "id": "street",
      "type": "text",
      "label": "Street",
      "binding": { "source": "$json", "path": "address.street" }
    },
    {
      "id": "postcode",
      "type": "text",
      "label": "Post Code",
      "binding": { "source": "$json", "path": "address.postcode" }
    },
    {
      "id": "country",
      "type": "select",
      "label": "Country",
      "binding": { "source": "$json", "path": "address.country" }
    }
  ]
}

$json vs No Binding

Propertybinding: $jsonNo binding
Initial value sourceRead from initialValues at pathEmpty / control's own defaultValue
Appears in getValues()Yes, at binding path keyYes, at control id key
Written to on changeYes (binding path in value map)Yes (control id in value map)
Key in values objectThe control's id (not the path)The control's id
Values Are Always Keyed by Control ID Regardless of the binding path, engine.getValues() always returns values keyed by the control's id. The binding path tells the engine where to read the initial value from — not what key to use in the returned values map.