You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 5 Next »

(this page was created automatically. In case of formatting issues, please visit the official Wiki Page)

Audience: Low‑code builders (Dynamic Content Editor) and developers wiring dynamic actions / elements.

0. Why The Data Hub Exists

App composer components often need lightweight shared state for itself, boardlet to boardlet communication (app scope) or app to app communication(global). The Data Hub provides:

  • Zero‑config ephemeral state (in‑memory, auto‑clears on reload)
  • Simple key/value API with three intention‑revealing scopes (Local → App → Global) to minimise accidental coupling
  • Deterministic merge & precedence so templates stay concise (<span v-pre>{{ someKey}}</span> just works with local override semantics)
  • Event reactivity through ON_DATA_HUB_CHANGE so elements can react declaratively when relevant data changes
  • A uniform contract consumed by the Dynamic Rendering Context so all dynamic elements read state the same way

Use it whenever you need transient cross‑action or cross‑element data that does not warrant persistence or a domain signal store.

1. When To Use (Decision Guide)

Situation Use Data Hub? Scope Rationale
Store last clicked table row for the same widget or filters used on by one boardlet Yes Local Highest precedence, isolated by Content Id
Share a filter across several widgets within one micro‑app Yes App Limited blast radius; survives page navigation inside the app
Share a settings across two apps (navigate to shared dashboard in another app) Yes Global Survive page navigation between app
Large dataset / pagination cache No — Use dedicated data service / API caching
Long‑term preferences No — Persist via backend or local storage layer

Rule of thumb: Start as Local, promote to App only when two or more contents collaborate, promote to Global only if truly cross‑app.

2. Core Mental Model

Three maps exist simultaneously:

  • Global Map (singleton for the session)
  • App Map (namespaced by current appKey)
  • Local Map (namespaced by contentId)

At render time they form the Dynamic Rendering Context:

context = {
  ...Global, ...App(appKey), ...Local(contentId),      // Flattened (precedence Local > App > Global)
  global: Global,
  app: App(appKey),
  local: Local(contentId),
  contentId,
  appKey,
  // further helpers (environmentOrigin, etc.)
}

Therefore a key like selection can exist at all three scopes. selection resolves to the Local value if present; if not then selection will come from App and then finally from Global. Scope (local, app, global) value always remains accessible via <scope>.selection.

3. How To Set Values (Action Editor)

Chain Dynamic Actions:

Action (Editor) Scope Impact
Local Data Hub: Set Value Mutates Local map for target contentId (calculated automatically)
App Data Hub: Set Value Mutates App map for inferred appKey
Global Data Hub: Set Value Mutates Global map

Each Set action defines a Parameters Map (rows). For each row you specify: Target Key, Source Type, Value/Expression.

Supported Source Patterns

Source Type Example Input Result
Literal true boolean true
Literal + \{\{variables\}\} Username \{\{global.currentUser.name\}\} Username John

Merge Semantics (Per Key)

Existing Value New Value Result
(absent) any Created
Plain object Plain object Shallow merge (new props overwrite)
Anything else anything Replacement

Tip: To force a full replace of a nested object, first set it to null, then set the new object.

4. Reading Values

  1. Direct in app composer components: <span v-pre>{{ selection.rowId }}</span> or explicit <span v-pre>{{ local.selection.rowId }}</span>
  2. Via Get actions inside an action chain when an intermediate action (e.g. API Invoke) needs the value.

Prefer direct template access; use Get sparingly to keep chains lean.

5. Reactivity With ON_DATA_HUB_CHANGE

ON_DATA_HUB_CHANGE is an element event you can attach actions to. Behind the scenes each dynamic element subscribes to the Data Hub state if (and only if) it declares this event. On any change (global/app/local) the element receives an event payload shaped like:

{
  "elementContext": "<the element's own context() snapshot>",
  ...local,
  ...app,
  ...global,
  "local": { /* local scope map */ },
  "app": { /* app scope map */ },
  "global": { /* global scope map */ }
}

Use cases:

  • Auto refresh detail panel when selection changes elsewhere
  • Trigger conditional API prefetch when a prerequisite key appears

Best Practices:

  • Scope your follow‑up actions: check for the specific key change (e.g. by storing a hash or using a Condition action) to avoid redundant work.
  • Avoid chaining expensive API calls on every minor unrelated key update; consider isolating keys by namespacing.

6. Practical Recipes

6.1 Store a Table Selection (Local)

Row Click → Local Set (selection = JSON Interpolated: { "rowId":"<span v-pre>{{clickedRow.id}}</span>", "ts":"<span v-pre>{{timestamp}}</span>" })

6.2 Use Selection In Button API Call

Button Click chain:

  1. Local Get (selection)
  2. Check context change (selection)
  3. API Invoke (body includes <span v-pre>{{selection.rowId}}</span>)
  4. Local Set (rowDetails = response)

6.3 Shared Filter Across Widgets

Input Change → App Set (activeFilter = user input). All boardlet reference activeFilter or app.activeFilter. Boardlet can also listen for On Data Hub Change

6.4 React To Data Changes

Add event ON_DATA_HUB_CHANGE to a panel element; first action is a Condition verifying selection changed; then API fetch details.

7. Naming & Collision Strategy

Pattern Guidance
Generic key reused widely Add prefix (report.filters, tbl.selection)
Temporary chain scratch values Prefix with underscore (_tempPayload) and keep Local

8. Cleaning / Resetting

  • Provide a Clear Local Data On destroy event
  • Navigation: optionally clear App keys via dedicated Clear action (if available) or set them to neutral defaults
  • To purge multiple nested leftovers, replace parent object instead of merging

9. Troubleshooting Quick Table

Symptom Cause Fix
Blank interpolation Key not set yet Ensure Set runs first; default <span v-pre>{{ myKey || '—' }}</span>
Stale nested data Shallow merge kept old props Set to null then replace OR overwrite all fields
Unexpected override Same key at Local/App Namespace or explicit global. / app. access

10. Technical Reference (For Developers)

10.1 Precedence & Event Wiring

  • Merge order inside context(): Global < App < Local.
  • DynamicElementComponentV2 registers a watchState on the injected DataHub only if ON_DATA_HUB_CHANGE is configured, pushing merged maps (local/app/global) plus flattened keys to action invocations.
  • Event enumeration: DynamicEventTypes.ON_DATA_HUB_CHANGE (see dynamic-event-type.ts) and option with translate key DynamicActions.Shared.Events.ON_DATA_HUB_CHANGE (see dynamic-event-options.const.ts).

10.2 Event Payload Shape (Simplified)

interface DataHubChangePayload {
  elementContext: Record<string, unknown>;
  // flattened merged keys (local > app > global)
  // plus explicit namespaces:
  local: Record<string, unknown>;
  app: Record<string, unknown>;
  global: Record<string, unknown>;
  // other flattened keys appear at top level
}

10.3 Merge Algorithm (Set Value Actions)

Pseudo:

for (const key of Object.keys(incoming)) {
  const current = existing[key];
  const nextVal = incoming[key];
  if (current === undefined) {
    existing[key] = nextVal;
  } else if (isPlainObject(current) && isPlainObject(nextVal)) {
    existing[key] = { ...current, ...nextVal };
  } else {
    existing[key] = nextVal;
  }
}

10.4 Performance Notes

  • Shallow object merge keeps cost low; avoid nesting large mutable graphs under one key.
  • distinctUntilChanged with deep equality (E1Utility.isEqual) throttles ON_DATA_HUB_CHANGE dispatches; still avoid high‑frequency churn (e.g. rapid typing) unless necessary.
  • No labels