Skip to content

A master-detail page with a child grid

When you need this

A list where clicking a row opens a panel showing that record plus a list of its children — a category and its equipment types, a maintenance record and its line items, a checkout and its history.

The shape

  1. The master grid — a normal core.grid wired via metadata.dataSource.
  2. rowClicked on the grid runs an action chain that:
    • fetches the master record → page.detailRecord;
    • calls a parameterized Data Service for the children, passing the master id → page.childItems;
    • opens page.detailDialogOpen.
  3. A core.dialog bound to page.detailDialogOpen containing an overview card bound to page.detailRecord.* and a core.list (or nested core.grid) bound to page.childItems.

The rowClicked chain

json
"events": { "rowClicked": { "source": "action-chain", "actions": [
  { "id": "a0", "order": 0, "type": "callApi",
    "config": { "connectionRef": "self", "path": "/api/v1/entities/oeq_category/records/${event.id}", "httpMethod": "GET", "params": {} },
    "output": "detail" },
  { "id": "a1", "order": 1, "type": "setValue", "config": { "field": "page.detailRecord", "value": "${detail}" } },
  { "id": "a2", "order": 2, "type": "callApi",
    "config": { "connectionRef": "self", "path": "/api/v1/data-services/oeq-type-list/execute", "httpMethod": "POST",
      "params": { "parameters": { "parentId": "${event.id}" } } },
    "output": "children" },
  { "id": "a3", "order": 3, "type": "setValue", "config": { "field": "page.childItems", "value": "${children.rows}" } },
  { "id": "a4", "order": 4, "type": "setValue", "config": { "field": "page.detailDialogOpen", "value": true } }
] } }

The child Data Service

json
{
  "name": "oeq-type-list",
  "definition": {
    "operation": "search",
    "source": { "kind": "entity", "entityName": "oeq_type" },
    "filters": [ { "field": "category_id", "operator": "eq", "value": "${param.parentId}" } ],
    "parameters": [ { "name": "parentId", "type": "string" } ]
  }
}

The child list block

json
{
  "blockType": "core.list",
  "properties": {
    "items": { "source": "binding", "binding": { "scope": "page", "key": "childItems" } },
    "primaryPath": { "source": "static", "value": "name" },
    "secondaryPath": { "source": "static", "value": "code" }
  }
}

The rules that bite

  • ${event.id} is the clicked master row's id — available in rowClicked.
  • A parameterized Data Service is called with args nested under parameters: { "params": { "parameters": { "parentId": "..." } } }.
  • Bind the child list to ${children.rows} (or .items / .records — check the service's response envelope).
  • To let the panel add a child, put a small form + "Add" button in the same dialog whose chain POSTs to the child entity then re-runs the child Data Service. The tutorial's Equipment Catalog page does exactly this.