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 of InvoiceLineItems
  • parentLookupColumn, 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

  1. Pre-flight validates parent + every visible child row
  2. Primary write creates the parent invoice, returning its new id
  3. 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 readOnly flag, or an enableIf whose expression is false there.
  • Pre-populate child rows from a template: in onLoad, check displayMode === "new", then call addRow() with the template values.
  • Limit max rows: set maxRows on the LinkedList properties.