Common pattern: parent / child (LinkedList)
Invoice line items, attendees, expenses, capture multiple child rows on one parent form, all in one save.
When the parent record (an invoice, an event, a reimbursement) has any number of related rows (line items, attendees, expenses), you reach for the
LinkedList component.
The data
Two SharePoint lists in the same site:
- Invoices, Title, Customer (Lookup), Total (Currency), …
- InvoiceLineItems, Description, Quantity (Number), UnitPrice (Currency), LineTotal (Calculated: Quantity * UnitPrice), Invoice (Lookup → Invoices)
The Lookup column on the child list is the join, every line item points at one parent invoice.
On your form
Bound to the Invoices list. Add a LinkedList component and configure:
linkedListId, the GUID ofInvoiceLineItemsparentLookupColumn,Invoice(the join column on the child list)columns, which child columns to show as editable cells (e.g. Description, Quantity, UnitPrice; leave LineTotal out, it's calculated server-side)
How save works
- Pre-flight validates parent + every visible child row
- Primary write creates the parent invoice, returning its new id
- Post-save iterates every LinkedList row and writes child items with the parent's id as the Lookup value
Deleting a row in the LinkedList marks it for delete; on save, the child item is actually deleted.
Computing parent totals from child rows
In the form's Code drawer:
Sum line totals into the parent's Total field
function recomputeTotal() {
const rows = f365.control('LineItems').asLinkedList()?.rows() ?? [];
const total = rows.reduce(
(sum, r) => sum + (Number(r.Quantity) || 0) * (Number(r.UnitPrice) || 0),
0
);
f365.field('Total').value = total;
}
f365.events.onLoad(() => recomputeTotal());
f365.control('LineItems').on('row-change', recomputeTotal);
f365.control('LineItems').on('row-added', recomputeTotal);
f365.control('LineItems').on('row-removed', recomputeTotal);
Variations
- Read-only child list on display forms: nothing to configure. A form opened in
Display mode is read-only throughout, LinkedList included. To lock the rows on an
Edit form as well, use the field's
readOnlyflag, or anenableIfwhose expression is false there. - Pre-populate child rows from a template: in
onLoad, checkdisplayMode === "new", then calladdRow()with the template values. - Limit max rows: set
maxRowson the LinkedList properties.