Skip to content

Hold submit until embedded work drains

Forms and configurationDashboardHTTPx-lt-submit-guardx-lt-widget: escalation-listx-lt-actionsautoResolveWhenEmpty

A parent form's submit stays disabled while its child rows are open, and can close itself the moment the last one resolves.

The situation

A picker closes out an order after picking each of its items. Each item is its own row, claimed to the picker. The order should not close while any item is still open, and the picker should not have to leave the page to finish them.

The recipe

Declare the child query once and use it for the list, its inline actions, and the guard:

form_schema
{
"x-lt-submit-guard": {
"query": { "role": "order-items", "facets": { "orderId": "{{metadata.orderId}}" }, "assigned": "me" },
"message": "{{count}} item(s) still pending. Pick them before closing the order.",
"autoResolveWhenEmpty": true
},
"type": "object",
"properties": {
"items": {
"type": "string",
"readOnly": true,
"x-lt-widget": "escalation-list",
"x-lt-query": { "role": "order-items", "facets": { "orderId": "{{metadata.orderId}}" }, "assigned": "me" },
"x-lt-actions": [
{ "label": "Picked", "resolverPayload": { "picked": true, "orderId": "{{metadata.orderId}}" } }
]
}
}
}

The picker clicks Picked on each row. The count beside the locked submit falls with each click, and with autoResolveWhenEmpty the order submits itself once the query is confirmed empty.

The guarantee

Only a confirmed empty read clears the gate: while loading, on an error or on a 403, the submit stays disabled. For enforce_schema roles the server runs the same query at resolve and rejects with a canonical 422 while it returns rows, counting the true children regardless of the resolver’s read scope. The guard and the embedded list resolve through one shared mapping, so the count and the visible rows always agree. See Forms.