Concorde decorator — @handle. @handle(...keys) calls the decorated method each time a publisher assigns one of up to three store paths, with one typed argument per key. Nothing is stored on the component: use it for derived values Doc ID: docs/decorators/handle. Keywords: Concorde, supersoniks, docs/decorators/handle, handle, @handle, decorator, @handle(...keys), null, undefined, ${prop}, waitForAllDefined: true, ${name}, please proceed to gate ${gate}., skip. URL: https://concorde.supersoniks.org/docs/decorators/handle.
@handle
@handle(...keys) calls the decorated method each time a publisher assigns one of up to three store paths, with one typed argument per key. Nothing is stored on the component: use it for derived values and side effects, and @subscribe when you only need the value. See Data flow for the overall model.
Import
import { handle, Skip } from "@supersoniks/concorde/decorators";
import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
const cockpitKey = new DataProviderKey<{ altitude: number }>("cockpit");
@handle(cockpitKey.altitude)
onAltitude(feet: number) {
this.meters = Math.round(feet * 0.3048);
}
Basic usage
The method runs once with the current value when the component connects, then on every assignment, including null and undefined. Below, each climb assigns a new altitude and the method derives meters and flight level.
<docs-demo-sources for="demo-handle"></docs-demo-sources>
<demo-handle></demo-handle>
Dynamic path
${prop} placeholders resolve from properties of the same component; when one changes, the method is called with the value at the new path. Rules: Dynamic paths.
const personKey = new DataProviderKey<OnBoard, { seatIndex: number }>(
"demoOnBoard.${seatIndex}",
);
@property({ type: Number }) seatIndex = 0;
@handle(personKey)
onPerson(person: OnBoard | null) {
this.announcement = person ? `${person.name}, please proceed to gate B12.` : "";
}
<docs-demo-sources for="demo-handle-dynamic"></docs-demo-sources>
<demo-handle-dynamic></demo-handle-dynamic>
Multiple keys
Pass up to three DataProviderKey values; the method receives one argument per key, in the same order. Any assignment to any key calls it, so other arguments may still be null.
const flightKey = new DataProviderKey<{ status: string; gate: string }>("flight");
const weatherKey = new DataProviderKey<{ turbulence: boolean }>("weather");
@handle(flightKey.status, weatherKey.turbulence)
onConditions(status: string, turbulence: boolean) {
this.seatbeltSign = status === "boarding" || turbulence === true;
}
Wait for all values
With waitForAllDefined: true, the method runs only once every key holds a value other than null or undefined.
@handle(flightKey.gate, passengerKey.name, { waitForAllDefined: true })
announce(gate: string, name: string) {
this.message = `${name}, please proceed to gate ${gate}.`;
}
Skip values
skip lists categories of values that must not call the method. A category is a named test, not a value to compare.
| Category | Matches |
|---|---|
Skip.Nullish |
null or undefined |
Skip.EmptyString |
"" |
Skip.EmptyObject |
{} (arrays excluded) |
Skip.EmptyArray |
[] |
@handle(passengerKey, { skip: [Skip.Nullish, Skip.EmptyObject] })
onPassenger(passenger: Passenger) {
// not called while the publisher still holds {} (not loaded yet)
this.displayName = passenger.name;
}
To reject a specific value, return early inside the method.
API reference
| Argument | Type | Description |
|---|---|---|
key (1 to 3) |
DataProviderKey<T, U> |
Paths to watch; the method receives one value per key, in order |
options.waitForAllDefined |
boolean (default false) |
Call the method only when no value is null or undefined |
options.skip |
Skip[] (default none) |
Do not call the method when any value matches one of these categories |
options.skipEmptyPlaceholder |
boolean (default false) |
Treat a placeholder resolved to "" as not ready |
options, if present, is the last argument. @handle replaces the deprecated @onAssign: @onAssign("a", "b") is @handle(keyA, keyB, { waitForAllDefined: true }).