AI: JSON authoring rules
This page defines how an agent must construct NGX View Builder JSON.
Read the layout model first
A structure has two independent halves: pages is a layout tree of positions, elements is a flat dictionary of definitions, and elementRef is the only bridge between them. Containers do not hold their children; the column that references a container holds them in its own rows. Widths belong to elements, never to columns. The complete rules, with the exact object shapes and a full worked example, are in Layout model. Do not write layout JSON before reading it.
Minimal skeleton
{
"settings": {
"language": "en",
"locale": "en-US",
"renderMode": "page"
},
"pages": [
{
"name": "page1",
"rows": [
{
"columns": [
{ "elementRef": "field1" }
]
}
]
}
],
"elements": {
"page1": {
"name": "page1",
"label": "Page 1",
"type": "page"
},
"field1": {
"name": "field1",
"label": "Field 1",
"type": "text"
}
},
"localization": {
"defaultLanguage": "en",
"languages": ["en"]
}
}Element type name rules
Type strings are case-sensitive. Copy them exactly. Never invent casing variants.
| Correct | Wrong (do not use) |
|---|---|
"datepicker" | "datePicker", "DatePicker", "date-picker" |
"singleCheckbox" | "SingleCheckbox", "single_checkbox" |
"dynamicTable" | "DynamicTable", "dynamic-table" |
"dynamicPanel" | "DynamicPanel" |
"multiSelect" | "MultiSelect", "multi-select" |
"toggleSwitch" | "ToggleSwitch", "toggle-switch" |
"richText" | "richtext", "RichText" |
"fileUpload" | "fileupload", "FileUpload" |
"phoneInput" | "PhoneInput", "phone-input" |
"listGrid" | "ListGrid", "list-grid" |
The canonical full list is in Common mistakes, entry 14.
Structure rules
settings
- Keep only settings that are actually used.
- If the user does not request a complex modal/dialog mode,
language,locale, andrenderModeare sufficient. - Do not invent unnecessary
dialog*,stepper*, orpageNavigation*properties if they are not in use.
pages
pagesdescribes layout only.- Every page must have a
nameand arowsarray. Those are its only structural keys. - A row object has exactly one key:
columns. - A column object has
elementRef, plusrowsortabRowswhen it references a container. Nothing else.width,mobileWidth,span,label,typeon a column are silently dropped. rows[*].columns[*].elementRefis a string key into theelementsmap, not an object.- Do not embed full element objects inside
pages. - A
pageis a step or screen. Titled sections on one screen arepanelelements inside a single page, not separate pages.
elements
elementsis an object, not an array, and it is flat. It never nests.- The key must match
element.name. - Every element must have at least
name,label, andtype. - If
pages[*].name = "pageCustomer", there must be anelements.pageCustomerentry withtype: "page". - No element definition lists its children.
rows,columns,children,items,fieldson apanel/dynamicPanel/tabs/dialogdo not exist and are ignored. The exception is the two tables, whose cells are not layout:tabledeclares them incolumnsConfigkeyed bykey, anddynamicTabledeclares them incolumnskeyed byname.
localization
- For a single-language form, the minimum is:
defaultLanguagelanguages
- For multi-language forms, a
textssection may also be present.
dataSources
- Create only when the user genuinely needs external data or actions.
dataSourceNamereferences in elements must point to a real datasource.- If the form has no integration scenarios, it is better to omit
dataSources.
Name and reference rules
- All
namevalues must be unique throughout the structure. elementRefmust point to an existingelementsentry.- If an element is a container with inner fields, those child elements must also have unique
namevalues. - Do not reuse the same
namefor multiple different elements.
What the agent must do when extending an existing form
- Preserve existing
settings,pages,elements,localization, anddataSourcesunless the user explicitly asks to rebuild everything from scratch. - Modify only the related sections.
- When adding a new element, you must:
- add it to
elements - insert the
elementRefin the appropriatepage/row/column
- add it to
- When adding logic between fields, verify that both fields already exist.
Layout rules
- A single
rowis a horizontal band; itscolumnssit side by side. Vertical order is the order ofrows. - A column with no width takes an equal share of the row. For a two-column layout, one
rowwith twocolumnsand no widths is sufficient. Never write"width": "50%"to get halves. - Widths (
width,tabletWidth,mobileWidth,fitContent) are element properties, set in theelementsmap, and only when the split must be uneven. - Exactly ten types accept children:
page,panel,dynamicPanel,dialog,emptyBlock(viacolumn.rows) andtabs,tabsPro,accordion,splitter,progressFlow(viacolumn.tabRows, keyed by each tab/item/panel/stepvalue). Every other type is a leaf. - Container inner layouts must remain in the NGX View Builder model, not via custom HTML.
parentNameis not how parentage is declared. The layout tree is.
Worked examples and the exact interfaces: Layout model.
Value shape rules
text,textarea,richTexttypically store astring.number,sliderstore anumberorstringdepending onvalueStorageType.singleCheckbox,toggleSwitch,toggleButtontypically store aboolean.checkbox,multiSelecttypically store an array.select,radio,autocompletetypically store a single value.dateRangemust return an object withdateFromanddateTo.dynamicPanelanddynamicTabletypically store an array of objects.numberStepperstores anumber;timePickerstores a time string.signaturePadstores signature image data keyed under the element'sname.listBox,selectButtonstore a single value, or an array when multi-select/multipleis enabled.progressBarstores anumber.
Logic rules
- Use
visibleIf,disableIf,requireIf,readonlyIf,resetIffor boolean conditions. - Use
expressionto compute and write a value. - When logic depends on changes in another field, typically add
logicExecutionMode: "onChange". - Do not use self-reference
expression.
Validator field rules
Validators are separate sub-objects in the validators array. They have their own field names that differ from element-level logic fields:
| Element-level (correct placement) | Validator-level (correct placement) |
|---|---|
element.visibleIf | validator.condition |
element.requireIf | validator.applyIf |
element.expression | (does not exist on validators) |
Never put visibleIf, requireIf, readonlyIf, disableIf, expression, or resetIf inside a validator object. Never use the field name expression on a validator; the correct field is condition.
Polarity: condition is the failing check. The validator error is shown while condition evaluates to true. Use applyIf to run a validator only in certain cases (it runs while applyIf is truthy).
Correct:
{
"name": "age",
"type": "number",
"visibleIf": "{skipAge} != true",
"validators": [
{ "type": "min", "value": 0, "message": "Cannot be negative" },
{ "type": "max", "value": 120, "message": "Invalid age", "applyIf": "{country} == 'LT'" }
]
}What must not be generated
- Custom
Angularcomponents. - Non-existent NGX View Builder properties.
- Full element objects embedded in
pages. - Pseudo-code instead of real JSON.
- Empty wrappers or meta-properties with no real purpose.
Pre-return checklist
- Do all
elementRefvalues point to an existing element. - Does every
pagehave a correspondingelements[pageName]entry. - Do logic fields return the correct type.
- Are there no self-reference expressions.
- Is the correct element chosen for the task.
- Are there no unnecessary properties added.
- Are all
typestrings exact-cased (e.g.datepicker, notdatePicker)? - Do validators use
condition(error whentrue) andapplyIf, rather thanexpression,visibleIf, or other element-level field names? - Is every container's content attached to the referencing column, and does no element definition contain a
rows/children/itemsarray? - Do all column objects carry only
elementRef(plusrows/tabRowswhere applicable), with no widths or other properties?
