Foundation Forms UI schema
Most renderers are defined directly in the jsonSchema
that comes from the server, but there are also those that you can add via uiSchema
.
You can control the appearance of your form using the UI Schema to describe the layout of your form. This describes the different UI schema elements that appear in your form.
Examples
Customisable UI schema
Here is an example of a UI schema we could use with the JSON schema we described in the previous page.
In this UISchema:
- the SIMPLE_TRADE_ID field is hidden
- the label is overridden for QUANTITY and SIDE
- an options configuration has been provided for SIDE, which will render a comboxbox
The combobox accepts an array of objects. You can specify the object property for option value for each option with valueField
and the option display value with labelField
.
- Genesis
- React
- Angular
Declaration:
<foundation-form
design-system-prefix="rapid"
:jsonSchema="${sampleJsonSchema}"
:uischema="${simpleTradeUiSchema}"
></foundation-form>
Usage:
const sampleJsonSchema = {
type: 'object',
properties: {
QUANTITY: {
type: 'number',
description: 'kotlin.Double',
},
SIDE: {
type: 'string',
description: 'kotlin.String',
},
},
};
export const simpleTradeUiSchema: UiSchema = {
type: 'VerticalLayout',
elements: [
{
type: 'Control',
scope: '#/properties/SIMPLE_TRADE_ID',
options: {
hidden: true
}
},
{
type: 'Control',
scope: '#/properties/QUANTITY',
label: 'Enter Quantity:'
},
{
type: 'Control',
scope: '#/properties/SIDE',
options: <ConnectedRenderersOptions>{
data: [
{ label: 'Buy', value: 'BUY' },
{ label: 'Sell', value: 'SELL' }
],
valueField: 'value',
labelField: 'label',
}
}
]
}
@customElement({
name: 'form-example',
template: html`
<foundation-form
design-system-prefix="rapid"
:jsonSchema="${sampleJsonSchema}"
:uischema="${simpleTradeUiSchema}"
></foundation-form>
`,
})
export class FormExample extends GenesisElement {}
Declaration:
<foundation-form
design-system-prefix="rapid"
jsonSchema={sampleJsonSchema}
uischema=${simpleTradeUiSchema}
></foundation-form>
Usage:
const sampleJsonSchema = {
type: 'object',
properties: {
QUANTITY: {
type: 'number',
description: 'kotlin.Double',
},
SIDE: {
type: 'string',
description: 'kotlin.String',
},
},
};
export const simpleTradeUiSchema: UiSchema = {
type: 'VerticalLayout',
elements: [
{
type: 'Control',
scope: '#/properties/SIMPLE_TRADE_ID',
options: {
hidden: true
}
},
{
type: 'Control',
scope: '#/properties/QUANTITY',
label: 'Enter Quantity:'
},
{
type: 'Control',
scope: '#/properties/SIDE',
options: <ConnectedRenderersOptions>{
data: [
{ label: 'Buy', value: 'BUY' },
{ label: 'Sell', value: 'SELL' }
],
valueField: 'value',
labelField: 'label',
}
}
]
}
export default function FormExample({}) {
return (
<foundation-form
design-system-prefix="rapid"
jsonSchema={sampleJsonSchema}
uischema=${simpleTradeUiSchema}
></foundation-form>
);
}
Declaration
<foundation-form
design-system-prefix="rapid"
[jsonSchema]="jsonSchema"
[uischema]="uiSchema"
></foundation-form>
Usage
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule } from '@angular/forms';
const sampleJsonSchema = {
type: 'object',
properties: {
QUANTITY: {
type: 'number',
description: 'kotlin.Double',
},
SIDE: {
type: 'string',
description: 'kotlin.String',
},
},
};
export const simpleTradeUiSchema: UiSchema = {
type: 'VerticalLayout',
elements: [
{
type: 'Control',
scope: '#/properties/SIMPLE_TRADE_ID',
options: {
hidden: true
}
},
{
type: 'Control',
scope: '#/properties/QUANTITY',
label: 'Enter Quantity:'
},
{
type: 'Control',
scope: '#/properties/SIDE',
options: <ConnectedRenderersOptions>{
data: [
{ label: 'Buy', value: 'BUY' },
{ label: 'Sell', value: 'SELL' }
],
valueField: 'value',
labelField: 'label',
}
}
]
}
@Component({
selector: 'my-root',
template: `
<foundation-form
design-system-prefix="rapid"
[jsonSchema]="jsonSchema"
[uischema]="uiSchema"
></foundation-form>
`,
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [FormsModule],
})
export class AppComponent {
jsonSchema = sampleJsonSchema;
uiSchema = simpleTradeUiSchema
}
It is important to note the scope
property in each UiSchemaElement.
Foreign-key relationship with UISchema
You can easily use foundation forms to enforce a foreign-key relationship between two entities.
Let's say you have two tables, COUNTERPARTY and TRADE, and the TRADE table has a foreign-key relationship on COUNTERPARTY_ID.
You can use the UISchema to show a list derived from the COUNTERPARTY table. You can make it user-friendly and show the NAME field for the label and the COUNTERPARTY_ID field for the value.
smart-forms-examples-dictionary.kts
tables {
...
table(name = "TRADE", id = 11_000) {
field("TRADE_ID", STRING).sequence("TR")
field("COUNTERPARTY_ID", INT).notNull()
field("NOTES", STRING)
field("PRICE", DOUBLE).notNull()
field("QUANTITY", STRING).notNull()
field("SIDE", ENUM("SELL","BUY")).default("BUY").notNull()
primaryKey("TRADE_ID")
}
table(name = "COUNTERPARTY", id = 11_001) {
field("COUNTERPARTY_ID", INT).notNull()
field("ENABLED", BOOLEAN).default(false).notNull()
field("MAIN_CONTACT", STRING).notNull()
field("NAME", STRING).notNull()
primaryKey("COUNTERPARTY_ID")
}
...
}
You must have a query in your Data Server to serve the contents of the COUNTERPARTY table.
dataServer {
...
query("ALL_COUNTERPARTIES", COUNTERPARTY)
...
}
In the UI schema, for the COUNTERPARTY_ID control:
-
Specify the
allOptionsResourceName
to be the value from your Data Server query - in this case,ALL_COUNTERPARTIES
. -
Set the
valueField
to beCOUNTERPARTY_ID
andlabelField
to beNAME
:
- Genesis
- React
- Angular
Declaration:
<foundation-form
design-system-prefix="rapid"
:jsonSchema="${sampleJsonSchema}"
:uischema="${simpleTradeUiSchema}"
></foundation-form>
Usage:
const sampleJsonSchema = {
type: 'object',
properties: {
TRADE_ID: {
type: 'string',
description: 'kotlin.String',
},
PRICE: {
type: 'number',
description: 'kotlin.Double',
},
NOTES: {
type: 'string',
description: 'kotlin.String',
},
COUNTERPARTY_ID: {
type: 'string',
description: 'kotlin.String',
},
QUANTITY: {
type: 'number',
description: 'kotlin.Double',
},
SIDE: {
type: 'string',
description: 'kotlin.String',
},
},
};
export const tradeUISchema: UiSchema = {
type: 'Control',
elements: [
{
type: 'Control',
scope: '#/properties/TRADE_ID',
options: {
hidden: true,
}
},
{
type: 'Control',
scope: '#/properties/SIDE',
options: <ConnectedRenderersOptions>{
data: [
{ label: 'Buy', value: 'BUY' },
{ label: 'Sell', value: 'SELL' }
],
valueField: 'value',
labelField: 'label',
}
},
{
type: 'Control',
scope: '#/properties/PRICE'
},
{
type: 'Control',
scope: '#/properties/QUANTITY'
},
{
type: 'Control',
scope: '#/properties/COUNTERPARTY_ID',
label: 'Counterparty',
options: {
allOptionsResourceName: 'ALL_COUNTERPARTIES',
valueField: 'COUNTERPARTY_ID',
labelField: 'NAME',
}
},
{
type: 'Control',
scope: '#/properties/NOTES',
options: {
textarea: true,
},
},
]
}
@customElement({
name: 'form-example',
template: html`
<foundation-form
design-system-prefix="rapid"
:jsonSchema="${sampleJsonSchema}"
:uischema="${simpleTradeUiSchema}"
></foundation-form>
`,
})
export class FormExample extends GenesisElement {}
Declaration:
<foundation-form
design-system-prefix="rapid"
jsonSchema={sampleJsonSchema}
uischema=${simpleTradeUiSchema}
></foundation-form>
Usage:
const sampleJsonSchema = {
type: 'object',
properties: {
TRADE_ID: {
type: 'string',
description: 'kotlin.String',
},
PRICE: {
type: 'number',
description: 'kotlin.Double',
},
NOTES: {
type: 'string',
description: 'kotlin.String',
},
COUNTERPARTY_ID: {
type: 'string',
description: 'kotlin.String',
},
QUANTITY: {
type: 'number',
description: 'kotlin.Double',
},
SIDE: {
type: 'string',
description: 'kotlin.String',
},
},
};
export const tradeUISchema: UiSchema = {
type: 'Control',
elements: [
{
type: 'Control',
scope: '#/properties/TRADE_ID',
options: {
hidden: true,
}
},
{
type: 'Control',
scope: '#/properties/SIDE',
options: <ConnectedRenderersOptions>{
data: [
{ label: 'Buy', value: 'BUY' },
{ label: 'Sell', value: 'SELL' }
],
valueField: 'value',
labelField: 'label',
}
},
{
type: 'Control',
scope: '#/properties/PRICE'
},
{
type: 'Control',
scope: '#/properties/QUANTITY'
},
{
type: 'Control',
scope: '#/properties/COUNTERPARTY_ID',
label: 'Counterparty',
options: {
allOptionsResourceName: 'ALL_COUNTERPARTIES',
valueField: 'COUNTERPARTY_ID',
labelField: 'NAME',
}
},
{
type: 'Control',
scope: '#/properties/NOTES',
options: {
textarea: true,
},
},
]
}
export default function FormExample({}) {
return (
<foundation-form
design-system-prefix="rapid"
jsonSchema={sampleJsonSchema}
uischema=${simpleTradeUiSchema}
></foundation-form>
);
}
Declaration
<foundation-form
design-system-prefix="rapid"
[jsonSchema]="jsonSchema"
[uischema]="uiSchema"
></foundation-form>
Usage
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormsModule } from '@angular/forms';
const sampleJsonSchema = {
type: 'object',
properties: {
TRADE_ID: {
type: 'string',
description: 'kotlin.String',
},
PRICE: {
type: 'number',
description: 'kotlin.Double',
},
NOTES: {
type: 'string',
description: 'kotlin.String',
},
COUNTERPARTY_ID: {
type: 'string',
description: 'kotlin.String',
},
QUANTITY: {
type: 'number',
description: 'kotlin.Double',
},
SIDE: {
type: 'string',
description: 'kotlin.String',
},
},
};
export const tradeUISchema: UiSchema = {
type: 'Control',
elements: [
{
type: 'Control',
scope: '#/properties/TRADE_ID',
options: {
hidden: true,
}
},
{
type: 'Control',
scope: '#/properties/SIDE',
options: <ConnectedRenderersOptions>{
data: [
{ label: 'Buy', value: 'BUY' },
{ label: 'Sell', value: 'SELL' }
],
valueField: 'value',
labelField: 'label',
}
},
{
type: 'Control',
scope: '#/properties/PRICE'
},
{
type: 'Control',
scope: '#/properties/QUANTITY'
},
{
type: 'Control',
scope: '#/properties/COUNTERPARTY_ID',
label: 'Counterparty',
options: {
allOptionsResourceName: 'ALL_COUNTERPARTIES',
valueField: 'COUNTERPARTY_ID',
labelField: 'NAME',
}
},
{
type: 'Control',
scope: '#/properties/NOTES',
options: {
textarea: true,
},
},
]
}
@Component({
selector: 'my-root',
template: `
<foundation-form
design-system-prefix="rapid"
[jsonSchema]="jsonSchema"
[uischema]="uiSchema"
></foundation-form>
`,
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [FormsModule],
})
export class AppComponent {
jsonSchema = sampleJsonSchema;
uiSchema = simpleTradeUiSchema
}
The resulting form looks like this, with the counterparty name displayed in the combobox.
There is much more you can do with the UiSchema
, such as specify layouts, rules for showing/hiding/enabling/disabling controls.
After you have looked at the basics here, you can find more details in our API Docs
Full source code at JSON/UI Schema example