Osy#betaRun it on Osyrin: osyrin.com

Reference / UI

Member selectors — a control prop that names a member of your row: xField: s => s.X

props { Func<TNode, double> xField = n => n.X; } · Canvas(nodes: steps, xField: s => s.Left)

A control prop declared Func<TRow, V> is a member selector: the call site writes `xField: s => s.X`, the compiler checks it against the row type the call binds, and the control receives that member's key. A misspelt member is a compile error naming the member and the type, where a string used to draw nothing.

stable1 example compiled by CIuicontrolsauthoringtypes

Summary#

Some controls read a particular member off each row the app hands them — a canvas reads each node's position, a picture reads which node an edge leaves from. The app says WHICH member with a selector, the same lambda it writes in LINQ:

FlowCanvas(nodes: steps, edges: links, nodeTypes: types,
           typeField: s => s.Kind, labelField: s => s.Title, edgeLabelField: e => e.Label);

The compiler resolves each selector over the row type, so a typo is a compile error at the call — not a node drawn at (0, 0) or an edge that never appears, which is what typeField: "Knd" did on a clean compile.

Signature#

control <Name><TRow> {
  props {
    TRow[] rows;
    Func<TRow, double> xField = r => r.X;   // a selector with a default: used when the row has that member
    Func<TRow, string>? labelField;         // optional: omitted means the control does without it
    Func<TRow, object> keyField = r => r.Key;   // `object`: any member (a row reference, or a key)
  }
}

Description#

What the call site may write#

ONE member of the row, read off the lambda's own parameter: s => s.X. The control's JavaScript reads that member off the row it was handed, so:

writtenanswer
s => s.Leftthe member Left
s => s.Lfetrefused: class 'Step' has no property 'Lfet'. Did you mean 'Left'? (entity for an entity row)
s => s.Title where a double is declaredrefused: 'xField' selects a double, but Step.Title is string — with the members that ARE doubles
s => s.Owner.Namerefused: one member, not a path — the row carries its own members only
s => s.Title + "!"refused: the control reads a member, so a computed value has nowhere to run
"Left"refused, with the selector to write and the members it could name

The declared return type is checked: an enum where the control wants text is refused, because it would reach the control as its number and match nothing.

A control with a selector prop#

class Step { public string Title; public double Left; public double Top; }

control Board<TNode> {
  contractVersion "1.1"
  participation headless
  props {
    TNode[] nodes;
    Func<TNode, double> xField = n => n.X;
    Func<TNode, double> yField = n => n.Y;
    Func<TNode, string>? labelField;
  }
}

[Route("/board")] [AllowAnonymous]
component BoardPage() {
  Step[] steps = [ new Step { Title = "Receive", Left = 40, Top = 60 },
                   new Step { Title = "Approve", Left = 340, Top = 40 } ];
  render {
    Board(nodes: steps, xField: s => s.Left, yField: s => s.Top, labelField: s => s.Title);
  }
}

What the control's JavaScript receives#

The member's KEY, as a string — props.xField is "Left", so the shim reads row[props.xField]. A selector prop left out arrives as undefined, and the shim applies the declared default (props.xField ?? 'X'), exactly as for any other defaulted prop. osy control build types it as xField?: string in the generated .control.d.ts.

DataGrid does not need one#

The kit's DataGrid is ordinary Osy#, so its columns RUN their selectors (Value = o => o.Reference, and computed ones like f => Text.ByteSize(f.Size)). The order it opens in is said on the column too — Sort = UiSort.Descending — see Acting on data — a calm grid header, filters as chips, and a toolbar that follows the selection.

See also#

Related

control — foreign UI controls (charts, grids, maps)

A `control` block declares the contract of a foreign UI widget — a chart, a data grid, a map — that a small JavaScript…

The flow kit — a node-and-edge canvas whose nodes are your own Osy#

A modelling canvas — pan, zoom, drag nodes, draw edges between ports, select and delete, by mouse and by keyboard —…

Laying a graph out — ranks, routed edges and a run's path on the flow canvas

How the flow canvas draws a directed graph by itself: nodes in ranks from the starts to the ends, the main path on one…

Acting on data — a calm grid header, filters as chips, and a toolbar that follows the selection

A DataGrid reads calmly: its per-column filter row is shut until somebody asks to filter (the Filter toggle, or a…

generic component

A component with type parameters, bound at each call site from the arguments — one component that works over any enum…