Detecting components
$UI.detect(container) scans a container for undetected components, elements
carrying a ui-type attribute or a cui-* custom tag and renders each
one it finds. container is optional, omit it to scan the whole page and the call
is awaitable. It runs automatically on DOMContentLoaded, no call needed on a
static page rendered by the server and left alone. Set $UI.autoDetect to
false before DOMContentLoaded fires to opt out and call
$UI.detect() manually instead.
That automatic pass only happens once. Any HTML injected afterward, a template applied, a
fragment fetched and inserted, a route loaded by a client-side router, needs its own call to
$UI.detect(), scoped to the container that was just added.
container.innerHTML = newHtml;
$UI.detect(container);
Bindary calls this for you after a route's view is injected, so components declared inside a
route's HTML are detected without any manual wiring. Building on top of a different
routing system or injecting HTML some other way, call $UI.detect() yourself once
the new markup is in the DOM. Passing the smallest container that actually changed keeps
detection fast, since it skips everything already rendered outside of it.
Waiting for a specific component
A component created in JavaScript already gives you a direct hook, its own
events.onPostRender fires once that specific instance is done, no polling or
guessing needed.
const combo = $UI.createComponent(componyx.UI.ComboBox, { id: 'demoCombo', containerElement: document.body });
combo.events.onPostRender.once(() => combo.focus());
combo.show();
A component declared in HTML renders through the automatic detection pass instead. Check
renderState to see whether that pass has already reached it and fall back to
the global $UI.onPostRender, which fires once a whole batch of detected
components finishes rendering, to catch the moment it does.
if ($UI.store.myButton?.renderState == 2) // RenderState: 0 NONE, 1 RENDERING, 2 RENDERED
{
$UI.store.myButton.enable();
}
else
{
$UI.onPostRender.add(() => $UI.store.myButton.enable());
}
The numeric states are also available as $base.static.RenderState.NONE,
.RENDERING and .RENDERED, if you'd rather reference the enum than
the literal.
With $UI.autoDetect set to false, UI components have not been
detected yet on page load. So a component declared in HTML is guaranteed not to be rendered
until you call $UI.detect() yourself, the same pattern used for a route or view
change below.
Detecting after a route or view change
A server-rendered page with no client-side router only ever needs the automatic pass above.
A single-page application needs its own $UI.detect() call after each new view's
HTML lands in the DOM, this applies to any router that injects views separately, Bindary
included, only where that call belongs differs per router.
Bindary's routes expose a postLoad event for this, firing once the route's view
is rendered. Paired with $UI.onPostRender here so code waiting on a specific
component runs whether that component was already detected by the time this handler executes,
or gets detected moments later.
ctrl.postLoad = async () =>
{
if (!_UIDetected)
{
$UI.onPostRender.once(() =>
{
_UIRendered = true;
$UI.store.myButton.enable();
});
_UIDetected = true;
let detected = await $UI.detect(); // detect UI controls
if (!detected.length)
$UI.onPostRender.fire();
}
};
_UIDetected and _UIRendered are plain flags the route's own
controller defines to guard against detecting the same view twice, not part of Componyx.UI
itself. The last check matters: $UI.onPostRender only fires once a detected
batch finishes rendering, so a view with nothing left to detect fires it manually to unblock
the handler above.