Skip to main content
cngx-src documentation

createMaterialBidirectionalSync

Functioncommon/data/material-bridge

projects/common/data/material-bridge/bidirectional-sync.ts

Description#

Single shared bidirectional-sync factory for cngx organisms / directives that bridge a cngx presenter against a Material parent (<mat-tab-group>, <mat-stepper>, etc.).

Lives at Level 2 in @cngx/common/data parallel to createCommitController. Material types never enter the signature — the caller maps Material-specific events and property accessors to a host-agnostic shape at the directive boundary.

Installs:

  1. A presenter→Material effect() that tracks presenterIndex and writes through writeSelectedIndex, equality-guarded against readSelectedIndex() to suppress redundant writes. The Material read+write pair runs inside untracked() per reference_signal_architecture rule 2.
  2. A Material→presenter subscription that forwards each selectionChange$ emission to onMaterialSelection (equality-guarded against presenterIndex() so a Material event whose value already matches the presenter is dropped — closes the re-entrancy loop).

Both sides clean up via destroyRef.

Material-eager-advance reconciliation. Material's MDC click handler advances selectedIndex before the Material→presenter subscription forwards the click. When the presenter HOLDS its index (pessimistic mode + bound commitAction), the subscriber does NOT write Material back: on a SUCCESSFUL commit the presenter later advances to the clicked target and Material is already there, so the mirror effect is a no-op (no flash); on a REJECTED commit the presenter never moves, leaving Material eager-advanced on the refused tab. The host detects the rejection through its own commit lifecycle and calls CngxMaterialBidirectionalSyncHandle.reconcile to snap Material back. Writing from inside the subscriber instead is unsafe: Material's selectedIndex read-back lags a programmatic write, so the mirror effect's equality guard reads a stale value and skips the corrective write, sticking the visual on the wrong tab.

Self-echo suppression (loop-safety). Every programmatic selectedIndex write makes Material re-emit selectionChange. The factory records each value it writes and drops the matching echo (indexOf + splice, which also prunes earlier writes whose echo Material coalesced away) before any other processing. This is load-bearing for an ASYNC commit-action: Material emits the echo a microtask later, by which point the commit may have advanced presenterIndex, so an equality-only guard (presenterIndex() === idx) would FAIL to drop the echo — it would re-enter the subscriber and ping-pong against the in-flight navigation (the demo freezes). Matching the echo by the value we wrote drops it regardless of where the presenter has moved.

Signature#

createMaterialBidirectionalSync(opts: CngxMaterialBidirectionalSyncOptions)

Parameters#

Returns#

CngxMaterialBidirectionalSyncHandle