Skip to content

Formbar Configuration

Formbar Configuration vs. Schematics Configuration

Section titled “Formbar Configuration vs. Schematics Configuration”

There are two configuration files used by ngx-formbar

  • Formbar Configuration: formbar.config.ts
  • Schematics Configuration: formbar.config.json

The schematics configuration is only used for the schematics and therefore only hold default values. This file is not relevant during runtime. All relevant options are shown on the schematics pages Generators and Register.

The configuration object that is used by the provideFormbar function has these properties

PropertyTypeRequiredDescription
componentRegistrationsRecord<string, Type>YesMapping between keys and controls.
validatorRegistrations[key]: (ValidatorFn | ValidatorKey)[]NoMapping between keys and validators.
asyncValidatorRegistrations[key]: (AsyncValidatorFn | ValidatorKey)[]NoMapping between keys and async validators.
updateOn’change’ | ‘blur’ \ | ‘submit’NoSpecifies when to update the control’s value.
globalConfigNgxFbGlobalConfigurationNoConfiguration that is used for all controls.

This configuration provides a global runtime configuration that is used by all controls, groups or blocks.

PropertyTypeRequiredDescription
testIdBuilderFn(content: NgxFbBaseContent,name: string,parentTestId?: string,) => string;YesFunction that is used to build the test id for a control

Registering all controls, validators, etc. directly in the app.config.ts is not ideal. ngx-formbar provides multiple approaches to organize your code better.

If you ran ng add with default parameters to install ngx-formbar your setup already is using split configurations.

This section assumes that you have read and understood the Registration Concepts and now how you need to set the configuration.

Create a file next to your app.config.ts with this content to get started. The defineFormbarConfig function is a helper that provides type support when defining the configuration in a separate file.

formbar.config.ts
import { defineFormbarConfig } from '@ngx-formbar/core';
export const formbarConfig = defineFormbarConfig({
componentRegistrations: {
// Component registrations go here
},
// validatorRegistrations are optional
validatorRegistrations: {
// Validator registrations go here
},
// asyncValidatorRegistrations are optional
asyncValidatorRegistrations: {
// Async Validator registrations go here
},
});

In app.config.ts use it like this:

app.config.ts
import { formbarConfig } from './formbar.config.ts';
export const appConfig: ApplicationConfig = {
providers: [
// other providers
provideFormbar(formbarConfig),
],
};

For more advanced code organization, you can leverage Angular’s dependency injection system by providing the tokens directly.

component-registrations.provider.ts
import { Type } from '@angular/core';
import { NGX_FW_COMPONENT_REGISTRATIONS } from '@ngx-formbar/core';
import { TextControlComponent } from './components/text-control.component';
import { GroupComponent } from './components/group.component';
import { InfoBlockComponent } from './components/info-block.component';
export const componentRegistrationsProvider = {
provide: NGX_FW_COMPONENT_REGISTRATIONS,
useValue: new Map<string, Type<unknown>>([
['text-control', TextControlComponent],
['group', GroupComponent],
['info', InfoBlockComponent],
// more registrations...
]),
};
validator-registrations.provider.ts
import { ValidatorFn, AsyncValidatorFn } from '@angular/forms';
import { NGX_FW_VALIDATOR_REGISTRATIONS, NGX_FW_ASYNC_VALIDATOR_REGISTRATIONS } from '@ngx-formbar/core';
import { Validators } from '@angular/forms';
import { letterValidator, noDuplicateValuesValidator, forbiddenLetterAValidator } from './validators';
import { asyncValidator, asyncGroupValidator } from './async-validators';
// Synchronous validators
export const validatorRegistrationsProvider = {
provide: NGX_FW_VALIDATOR_REGISTRATIONS,
useValue: new Map<string, ValidatorFn[]>([
['min-chars', [Validators.minLength(3)]],
['letter', [letterValidator]],
['combined', [Validators.minLength(3), Validators.required, letterValidator]],
['no-duplicates', [noDuplicateValuesValidator]],
['forbidden-letter-a', [forbiddenLetterAValidator]],
// more registrations...
]),
};
// Asynchronous validators
export const asyncValidatorRegistrationsProvider = {
provide: NGX_FW_ASYNC_VALIDATOR_REGISTRATIONS,
useValue: new Map<string, AsyncValidatorFn[]>([
['async', [asyncValidator]],
['async-group', [asyncGroupValidator]],
// more registrations...
]),
};

In app.config.ts use them like this:

app.config.ts
import { componentRegistrationsProvider } from './component-registrations.provider';
import { validatorRegistrationsProvider, asyncValidatorRegistrationsProvider } from './validator-registrations.provider';
export const appConfig: ApplicationConfig = {
providers: [
// other providers
provideFormbar(),
// Custom providers MUST come after provideFormbar()
componentRegistrationsProvider,
validatorRegistrationsProvider,
asyncValidatorRegistrationsProvider,
],
};

Multiple Configurations with Injection Tokens

Section titled “Multiple Configurations with Injection Tokens”

You can also provide multiple configuration objects that will be merged according to their resolution strategy:

split-configurations.provider.ts
import { NGX_FW_COMPONENT_REGISTRATIONS, NGX_FW_VALIDATOR_REGISTRATIONS, NGX_FW_CONFIG } from '@ngx-formbar/core';
// First set of components
export const baseComponentsProvider = {
provide: NGX_FW_COMPONENT_REGISTRATIONS,
useValue: new Map([
['text', TextComponent],
['number', NumberComponent],
]),
};
// Additional components from a different module
export const extraComponentsProvider = {
provide: NGX_FW_COMPONENT_REGISTRATIONS,
useValue: new Map([
['date', DateComponent],
['select', SelectComponent],
]),
};
// Multiple global configs will be deep merged
export const baseConfigProvider = {
provide: NGX_FW_CONFIG,
useValue: {
testIdBuilderFn: (baseName, controlName) => `${baseName}-${controlName}`,
},
};
export const moduleConfigProvider = {
provide: NGX_FW_CONFIG,
useValue: {
extraSettings: {
theme: 'dark',
},
},
};

For simpler scenarios, you can still split your registration files by type while using the provideFormbar() function.

Create a file with the following content, at whatever location makes sense.

controls.registerations.ts
export const componentRegistrations: ComponentRegistrationConfig = {
'text-control': TextControlComponent,
group: GroupComponent,
info: InfoBlockComponent,
// more regsitrations...
};

In app.config.ts use it like this

app.config.ts
import { componentRegistrations } from './controls.registerations.ts';
export const appConfig: ApplicationConfig = {
providers: [
// other providers
provideFormbar({
componentRegistrations,
}),
],
};

In formbar.config.ts use it like this

app.config.ts
import { componentRegistrations } from './controls.registerations.ts';
export const formbarConfig = defineFormbarConfig({
// other providers
componentRegistrations,
});

Create a file with the following content, at whatever location makes sense. You can also further split the files between sync and async validators

validators.registerations.ts
export const validatorRegistrations: ValidatorConfig<RegistrationRecord> = {
'min-chars': [Validators.minLength(3)],
letter: [letterValidator],
combined: ['min-chars', Validators.required, 'letter'],
'no-duplicates': [noDuplicateValuesValidator],
'forbidden-letter-a': [forbiddenLetterAValidator],
};
export const asyncValidatorRegistrations: AsyncValidatorConfig<RegistrationRecord> = {
async: [asyncValidator],
'async-group': [asyncGroupValidator],
};

In app.config.ts use it like this

app.config.ts
import { validatorRegistrations, asyncValidatorRegistrations } from './validators.registerations.ts';
export const appConfig: ApplicationConfig = {
providers: [
// other providers
provideFormbar({
validatorRegistrations,
asyncValidatorRegistrations,
}),
],
};

In formbar.config.ts use it like this

formbar.config.ts
import { componentRegistrations } from './controls.registerations.ts';
export const formbarConfig = defineFormbarConfig({
// other providers
componentRegistrations: {
validatorRegistrations,
asyncValidatorRegistrations,
},
});
misspelled.validators.registerations.ts
export const validatorRegistrations: ValidatorConfig<RegistrationRecord> = {
letter: [letterValidator],
// ⚠️ letter only spelled with one T.
// This will give an TS error in the provideFormbar function, but not in this case
combined: [Validators.required, 'leter'],
};

Global Configuration with Injection Tokens

Section titled “Global Configuration with Injection Tokens”

For advanced scenarios, you can provide global configuration options using the NGX_FW_CONFIG injection token.

global-config.provider.ts
import { NGX_FW_CONFIG } from '@ngx-formbar/core';
import { TestIdBuilderFn } from '@ngx-formbar/core';
// Example test ID builder function
const testIdBuilder: TestIdBuilderFn = (baseName, controlName) => {
return `${baseName}-${controlName}`;
};
export const globalConfigProvider = {
provide: NGX_FW_CONFIG,
useValue: {
testIdBuilderFn: testIdBuilder,
},
};

In app.config.ts use it like this:

app.config.ts
import { globalConfigProvider } from './global-config.provider';
export const appConfig: ApplicationConfig = {
providers: [
// other providers
provideFormbar(),
globalConfigProvider,
],
};