Advanced UI Patterns
While standard Forms and Grids cover 80% of use cases, complex enterprise applications require advanced layout orchestration. Struktural achieves this by linking LayoutNode definitions using UUIDs.
1. Embedded Grids (Master-Detail)
By default, placing a Collection node at the root of a Form's Layout array renders it as a bottom Tab. To embed a grid directly alongside the parent's data (Master-Detail):
UI Approach: Drag a Grid Widget inside a Group node on the canvas. Configure its Target Entity and Filter Field.
JSON Approach: Place a Collection node inside the Children array of a Group.
{
"Type": "Group",
"Label": "Active Tasks",
"Children": [
{
"Type": "Collection",
"Label": "Tasks",
"TargetViewId": "Task_Grid_1",
"ListProps": {
"TargetEntity": "ProjectTask",
"FilterField": "ProjectId",
"PageSize": 5
}
}
]
}
2. Tree and Linked Nested Form
For deep hierarchies (e.g., an Organization Chart with Departments and Employees), navigating back and forth between grids and forms loses context. You can render a Tree on the left and a reactive Form on the right.
UI Approach: Add a Tree Widget and a Linked Nested Form side-by-side. In the Tree properties, configure the mappings and select the Nested Form as the target.
JSON Approach: You must define two nodes and link them via the LinkedNestedFormUuid.
[
{
"_uuid": "tree-pane-uuid",
"Type": "Tree",
"ColSpan": 4,
"TreeProps": {
"RootEntity": "Department",
"LinkedNestedFormUuid": "form-pane-uuid",
"Mappings": [
{
"EntityName": "Department",
"ChildrenCollectionField": "Employees",
"TargetFormViewId": "Department_Form_1"
},
{
"EntityName": "Employee",
"TargetFormViewId": "Employee_Form_1"
}
]
}
},
{
"_uuid": "form-pane-uuid",
"Type": "NestedForm",
"ColSpan": 8
}
]
4. Conditional Formatting (FormattingRules)
Struktural allows you to dynamically change row or cell colors in Grids, Cards, and Calendars based on data values using Dynamic LINQ expressions.
UI Approach: In the View Editor, locate the Conditional Formatting section (in the main config pane for Grids, or the right-hand Properties pane for Map/Calendar widgets). Click Add Rule, write your Dynamic LINQ expression, and use the color pickers to select the Background and Text colors.
JSON Approach: Add a FormattingRules array to your GridViewDefinition (or Card/Calendar).
"FormattingRules": [
{
"Expression": "Status == \"Overdue\" AND DueDate < DateTime.UtcNow",
"BackgroundColor": "#ffcccc",
"TextColor": "#990000",
"Target": ""
},
{
"Expression": "TotalAmount > 10000",
"BackgroundColor": "#e6f7ff",
"Target": "TotalAmount"
}
]
(Note: If Target is empty, the entire row is colored. If Target is a field name, only that specific column cell is colored.)
5. Configuring Hierarchical RLS UI
When you use Hierarchical Row-Level Security (Materialized ACLs), administrators need a way to assign roles to specific records (e.g., assigning the "Manager" role to a specific "Folder").
This is done by embedding the system entity Struktural_Sys_RecordAcl inside the parent entity's form.
JSON Approach: Add a Collection node to the Form's Layout.
{
"Type": "Collection",
"Label": "Permissions",
"TargetViewId": "RecordAcl_Grid_1",
"ListProps": {
"TargetEntity": "Struktural_Sys_RecordAcl",
"FilterField": "RecordId"
}
}
3. Reactive Broadcasters (ListenToWidgetUuids)
Sometimes, selecting a row in Grid A should automatically filter the data shown in Grid B on the same screen.
UI Approach: In the Form Canvas, select the target widget (e.g., Grid B). In the right-hand Properties pane, expand Master-Detail Linking. Under "Listen To Selection From", check the boxes for any sibling widgets (e.g., Grid A) that should broadcast their selection state to this widget.
JSON Approach: Add the _uuid of the source widget to the ListenToWidgetUuids array in the target widget's properties.
[
{
"_uuid": "source-grid-uuid",
"Type": "Collection",
"TargetViewId": "Region_Grid",
"ListProps": { "TargetEntity": "Region" }
},
{
"_uuid": "target-grid-uuid",
"Type": "Collection",
"TargetViewId": "Store_Grid",
"ListProps": {
"TargetEntity": "Store",
"FilterField": "RegionId",
"ListenToWidgetUuids": [ "source-grid-uuid" ]
}
}
]