Skip to content

Sub-views

A sub-view embeds another view (a child grid or form) inside a parent form/view — for example the line items under an order, or the stock movements under a product. Declare them in <SubConfig> and place them in the layout with <Sub>.

<SubConfig>
<SubView Name="SaleItem" Label="Line Items" Icon="fa fa-list" Type="Table" RenderInView="Expanded" />
</SubConfig>

<SubView>: Name (the child view), Label, Icon, Color, Type (Table/Form), RenderInView (Disabled/Minimized/Expanded), NameColumn/LabelColumn, FormStyle, FormStyleColumn, ActivityTypeColumn, CustomJs, InMenu. Reference it from the layout with <Sub Name="SaleItem" />.

Each sub-view gets an icon button on every grid row by default. A view with many sub-views ends up with a row of icons that are hard to tell apart. Set InMenu="true" to list the sub-view in the row’s More (⋮) menu instead, by its Label and Icon. It opens exactly as it does from its button. Menu sub-views come first in the menu, ahead of Edit, Delete and row actions. When the row has no other menu items, the menu appears just for them.

<SubConfig>
<SubView Type="Table" Name="OrderLines" Label="Lines" Icon="fas fa-list" />
<SubView Type="Table" Name="OrderNotes" Label="Notes" Icon="fas fa-comments" InMenu="true" />
</SubConfig>

Keep the sub-views people open on most rows as buttons, and move the occasional ones into the menu. InMenu affects only the grid row. It has no effect on a <Sub> placed in a layout, or on RenderInView.

A <Sub> in a record’s view mode is read-only. It has no Add New, Edit, Delete, bulk delete or import. Row actions that run on the server (Sql, Script) are hidden too. Link and Report actions stay: they only open a URL or a document, so they change nothing. The actions column and its ⋮ menu therefore still appear when a child grid’s rows can only be opened through such a link, for example a report list with ViewAction="Disabled". To offer the server-run actions, also declare the child as a <SubView> on the grid row, where it is writable.

For a dynamic workflow task button, NameColumn supplies the form name or route, LabelColumn supplies its per-row label, FormStyleColumn chooses Modal/Redirected, and ActivityTypeColumn switches rows whose value is Route from opening a form to navigating:

<SubConfig>
<SubView Type="Form" Name="TaskAction" Label="Open Task" Icon="fas fa-play-circle"
NameColumn="ActivityRoute" LabelColumn="ActivityTitle"
ActivityTypeColumn="ActivityType" FormStyleColumn="ActivityFormStyle" />
</SubConfig>

When a sub-view loads (grid expand or <Sub> in a form/view), the parent row’s columns are passed to the child as @Parent__{Column} parameters — notably @Parent__Id (the parent’s primary key). So the child’s <Sql> filters by, and its <InsertSql> assigns the FK from, @Parent__Id — not the child’s own column name:

<Sql …> … WHERE si.IsDeleted = 0 AND (@Parent__Id IS NULL OR si.SaleId = @Parent__Id) </Sql>
<InsertSql>
INSERT INTO Sales.SaleItems (SaleId, ProductId, …) VALUES (TRY_CAST(@Parent__Id AS INT), @ProductId, …);
</InsertSql>

For editable line items, prefer a <CartTable> over a standalone <Sub>. The most direct shape is a view-backed cart — <CartTable View="OrderLines" ParentKey="OrderId" /> — where this same child view supplies the cart’s columns and its persistence, and doubles as the read-only View-mode panel (its SubView defaults to the child view). The cart drives all three modes (editable in Create/Edit, the read-only sub-view in View), so you never need a separate <Sub>. Use a standalone <Sub> only for child grids that aren’t backed by a cart.

Worked examples: sample/Inventory/models/views/Products.view.xml (kitchen-sink), sample/Inventory/models/views/PurchaseOrders.view.xml (sub-views + cart), sample/Inventory/models/views/PurchaseOrderLines.view.xml (child grid).