Skip to content

Events reference

All events live on NgxViewBuilderApiService and share a lightweight emitter API:

ts
const sub = api.onValueChanged.subscribe((e) => { ... });  // {unsubscribe()}
const dispose = api.onValueChanged.add(handler);           // returns disposer
api.onValueChanged.once(handler);
api.onValueChanged.remove(handler);

These are library emitters (not RxJS): subscribe returns { unsubscribe, closed }. Always detach in ngOnDestroy.

Events work the same in the runtime and renderer

<ngx-view-builder-runtime> and <ngx-view-builder-renderer> run on an isolated internal API instance, but every event they fire is automatically forwarded to the root NgxViewBuilderApiService your application injects — so the subscriptions below work identically on builder and runtime pages. (If you embed several runtimes on one page, use the payload's elementName/elementDataPath to tell them apart, or bridge instances yourself with the exported bridgeNgxViewBuilderApiEvents(source, target).)

Values & data

EventFires
onValueChanging / onValueChangeda field value is about to change / changed (dataPath, newValue, oldValue, sender, trigger)
onElementValueChanging / onElementValueChangedsame, enriched with element lookup + an api handle for the element
onElementPropertyChanging / onElementPropertyChangedan element property (label, hidden, disabled…) changes
ts
api.onElementValueChanged.add(({ elementDataPath, newValue, api: el }) => {
  if (elementDataPath === 'country') {
    void el.reloadDataSource('loadCities');
  }
});

Validation & completion

EventFires
onValidating / onValidatedvalidation runs / finishes (isValid, issues[])
onCompletethe form completes (Submit): { isValid, data, issues }
onSaveRequestedSave is requested from header or API

Structure & navigation

EventFires
onStructureChangedthe structure was edited
onCurrentPageChangedthe visible page changed
onDialogCloseda dialog-mode view closed (reason: 'close-button' | 'api')
onTabChanged / onTabChangeRequestedbuilder tab navigation
onLanguageChangedactive language switched

Rendering

EventFires
onBeforeRender / onRender / onAfterRenderview render phases (with render root)
onElementRender / onElementAfterRenderper-element render, with model + DOM handles

Use these for DOM-level integrations (tooltips, analytics attributes, measuring).

Element interactions

EventFires
onDynamicTableRowAdded / onDynamicTableRowRemoveda dynamicTable row was added / removed (elementName, rowIndex, row, rows, total)
onDynamicPanelItemAdded / onDynamicPanelItemRemoveda dynamicPanel item was added / removed (same payload shape)
onFileUploadFilesAdded / onFileUploadFileRemovedfiles were attached / a file was removed on a fileUpload (files, addedFiles / removedFile, removedIndex)
onElementTabChangedthe active tab of a tabs / tabsPro element changed (previousTabValue, tabValue, tabIndex)
onAccordionItemToggledan accordion section expanded or collapsed (itemIndex, itemValue, expanded)

All payloads carry elementName, elementDataPath, the element model, and a timestamp, so one subscription can serve many elements:

ts
api.onDynamicTableRowAdded.add(({ elementName, rowIndex, total }) => {
  if (elementName === 'familyMembers' && total >= 5) {
    api.showToast({ title: 'Limit', message: 'Max 5 members', variant: 'warning' });
  }
});

api.onDynamicPanelItemRemoved.add(({ elementDataPath, row }) => {
  this.audit.log('panel item removed', elementDataPath, row);
});

Data sources

EventFires
onDataSourceLoadingrequest started
onDataSourceLoadedsuccess (result, durationMs, fromCache)
onDataSourceLoadFailedfailure (error, errorMessage)
onDataSourceReloadedexplicit reload happened

Perfect for global spinners and error toasts:

ts
api.onDataSourceLoadFailed.add(({ sourceName, errorMessage }) =>
  api.showToast({ title: sourceName, message: errorMessage, variant: 'error' }));

Appearance & configuration

EventFires
onThemeModeChanged / onCustomThemeChangedtheme switches
onCssVariablesChanged / onCustomCssChanged / onCustomCssUrlsChangedstyle updates
onAiAssistantConfigChangedthe AI assistant backend config changed (config.backendUrl)

Templates & sidebar library

EventFires
onTemplateSaved / onTemplateDeleted / onTemplatesLoadedtemplate persistence hooks
onSidebarTemplateSaved, onSidebarGroupSaved / onSidebarGroupDeleted / onSidebarGroupsLoadedelement-library hooks

Tables

EventFires
onTableSettingsChanged / Applied / Requested / SaveRequestedcolumn layout lifecycle
onTableFiltersChanged / Appliedactive filters
onTableSavedFiltersChanged / Requested, onTableSavedFilterSaveRequestedsaved filter sets

Automation (plugins)

EventFires
onTriggerHandling / onTriggerHandledplatform triggers execute
onRuleEvaluating / onRuleEvaluatedrules engine runs (executedBranch)

Example — full save pipeline

ts
ngOnInit(): void {
  this.disposers.push(
    this.api.onComplete.add(async ({ isValid, data }) => {
      if (!isValid) return;
      const saved = await firstValueFrom(this.http.post('/api/forms', data));
      this.api.showToast({ title: 'Saved', variant: 'success' });
    }),
    this.api.onDataSourceLoadFailed.add((e) =>
      this.logger.error('DS failed', e.sourceName, e.errorMessage)),
  );
}

ngOnDestroy(): void {
  this.disposers.forEach((d) => d());
}