npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@olafvv/ngx-dynamic-form

v20.0.0

Published

This library is to create a form based on a JSON model. The forms is based on the `ReactiveFormsModule` from Angular and contains a set of pre-built form controls using the Angular Material library. Using the built-in form controls is optional, you can us

Readme

NgxDynamicForm

This library is to create a form based on a JSON model. The forms is based on the ReactiveFormsModule from Angular and contains a set of pre-built form controls using the Angular Material library. Using the built-in form controls is optional, you can use your own components to use as form controls inside the dynamic form. See Custom Form Controls form more information.

Table of contents

Getting started

1. Make sure to install and configure Angular Material if you want to use the built-in form controls
2. Install the library using npm:
npm i --save @olafvv/ngx-dynamic-form

Usage

1. Import the (standalone) component
import { DynamicFormComponent } from 'olafvv/ngx-dynamic-form';

@NgModule({
  //...
  imports: [DynamicFormComponent]
  //...
})
export class AppModule {}

Or when using a standalone application/components:

import { DynamicFormComponent } from '@olafvv/ngx-dynamic-form';

@Component({
  standalone: true,
  imports: [DynamicFormComponent]
  //...
})
export class AppComponent {
  //...
}
2. Define your form configuration

Create the JSON configuration for the form. This is a two-dimensional array where each array is a row in the form. So if you want multiple fields next to each other, define them in a single array. See Form layout for more information.

import { DynamicInput, DynamicTextarea, DynamicFormValidators } from '@olafvv/ngx-dynamic-form';

export const SAMPLE_FORM: DynamicFormConfig = [
  [
    new DynamicInput({
      name: 'name',
      inputType: 'text',
      label: 'Name'
    })
  ],
  [
    new DynamicInput({
      name: 'email',
      inputType: 'email',
      label: 'Email address'
    })
  ],
  [
    new DynamicTextarea({
      name: 'message',
      label: 'Your message',
      maxLength: 200,
      rows: 5
    })
  ]
];
3. Create a FormGroup

This library provides the service DynamicFormService which you can use to create a FormGroup based on the created form configuration.

import { SAMPLE_FORM } from './sample-form.ts';
import { DynamicFormService } from '@olafvv/ngx-dynamic-form;

@Component({
  //...
})
export class AppComponent {
  sampleFormConfig: DynamicFormConfig = SAMPLE_FORM;
  sampleFormGroup: FormGroup<SampleFormModel> = this.dynamicFormService.createFormGroup(this.sampleFormConfig);

  constructor(private dynamicFormService: DynamicFormService) {}
}
4. Add the dynamic-form inside the template

To add the form to your template, you have to use the selector <dynamic-form></dynamic-form> and pass the FormGroup and configuration as inputs:

<form [formGroup]="sampleFormGroup">
  <dynamic-form [group]="sampleFormGroup" [formConfig]="sampleFormConfig">
</form>

Validators

This library comes with a set of built-in validators, based on the Angular Validators. All provided validators are static methods inside the class DynamicFormValidators, each returning a DynamicFormValidator (e.g. DynamicFormValidators.required()).

To use the validators, pass them inside the validators array of the field configuration:

import { DynamicFormValidators } from '@olafvv/ngx-dynamic-form';

export const SAMPLE_FORM = [
  [
    new DynamicFormInput({
      //..
      validators: [DynamicFormValidators.required('Custom error message')]
    })
  ]
];

Built-in validators

Each validator has at least the optional parameter for a custom error message. If you don't provided one, the library will place a generic error message (e.g. for required: 'This field is required').

class DynamicFormValidators {
  // Validator that requires the control's value to be less than or equal to the provided number.
  static email(errorMessage?: string): DynamicFormValidator;
  // Validator that requires the control's value to be greater than or equal to the provided number.
  static min(min: number, errorMessage?: string): DynamicFormValidator;
  // Validator that requires the control's value to be less than or equal to the provided number.
  static max(max: number, errorMessage?: string): DynamicFormValidator;
  // Validator that requires the length of control's value to be greater than or equal to the provided number.
  static minLength(min: number, errorMessage?: string): DynamicFormValidator;
  // Validator that requires the length of control's value to be less than or equal to the provided number.
  static maxLength(max: number, errorMessage?: string): DynamicFormValidator;
  // Validator that requires the control's value to match the provided pattern.
  static pattern(pattern: string | RexExp, errorMessage?: string): DynamicFormValidator;
  // Validator that requires the control to have a non-empty value.
  static required(errorMessage?: string): DynamicFormValidator;
  // Validator that requires the control's value to be true.
  static requiredTrue(errorMessage?: string): DynamicFormValidator;
}

Custom Validators

Adding a custom validator is quite straightforward. All you have to do is to provide an object of the type DynamicFormValidator to the validators array of a field with a (unique) name, validatorFn and errorMessage.

Read more about creating custom Angular validators on the following page:

https://blog.angular-university.io/angular-custom-validators/

E.g. a validator to require a minimum time:

function minTimeValidatorFn(minTime: string): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    const inputTime = control.value as string;

    if (!inputTime) return null;

    const minTimeObj = new Date(`2000-01-01T${minTime}`);
    const inputTimeObj = new Date(`2000-01-01T${inputTime}`);

    return inputTimeObj >= minTimeObj ? null : { minTime: true };
  };
}

export const minTimeValidator: (minTime: string, msg?: string) => DynamicFormValidator = (minTime: string, msg?: string) => ({
  name: 'minTime',
  validator: minTimeValidatorFn(minTime),
  message: msg ?? `Minimale tijd is ${minTime}`
});
import { minTimeValidator } from './min-time-validator.ts';

//..

const formConfig: DynamicFormConfig = [
  [
    new DynamicInput({
      name: 'time',
      inputType: 'time',
      validators: [minTimeValidator('11:00')]
    })
  ]
];

Relations

Sometimes you want to create certain connections between fields in a form to control their state, based on the value of the other field. This library provides a way to configure these connections,called relations.

Each relation is defined on the field that requires a specific state based on one or more conditions. Each relation, a DynamicFormFieldRelation, contains an actionType, one or more condition(s) and optionally an operator.

interface DynamicFormFieldRelation {
  actionType: RelationActionType;
  conditions: RelationCondition[];
  operator?: RelationOperator;
}
Action type

The action type is the type of state the field should be when the conditions are met. Right now the library contains three different action types:

  • Disable/Enable
  • Visible/Hidden
  • Required/Optional

To set the type you have to use one of the provided enums:

enum RelationActionType {
  DISABLED = 'DISABLED',
  ENABLED = 'ENABLED',
  HIDDEN = 'HIDDEN',
  VISIBLE = 'VISIBLE',
  REQUIRED = 'REQUIRED',
  OPTIONAL = 'OPTIONAL'
}
Conditions

The conditions is an array of RelationCondition objects. Each condition contains the name of the field the related field is depended on and a value when the condition is met:

interface RelationCondition {
  // The name of the field this field is related to
  fieldName: string;
  // A method which has to return a boolean. Returning true means the condition is met
  value: (val: any) => boolean;
}
Operator

The operator is an optional property and determines if all or any one of the conditions have to return true to trigger the required state of the field. By default the value of this property is RelationOperator.AND and is only used when there are more than 1 conditions.

enum RelationOperator {
  // All conditions have to equal true
  AND = 'AND',
  // On of the conditions have to equal true
  OR = 'OR'
}
Example

Here is an example of a field called 'passportNumber' which has to be visible when the value of the field named 'documentType' equals to 'passport':

const formConfig = [
  [
    new DynamicSelect({
      name: 'documentType',
      label: 'Document type',
      options: [
        { label: 'Passport', value: 'passport' }
        //..
      ]
    })
  ][
    new DymamicInput({
      name: 'passportNumber',
      label: 'Passport number',
      relations: [
        {
          actionType: RelationActionType.VISIBLE,
          conditions: [
            {
              fieldName: 'documentType',
              value: (val: string) => val === 'passport'
            }
          ]
        }
      ]
    })
  ]
];

Built-in form controls

The library comes with a set of built-in form controls, using the Angular Material library. To make use of these you have to make sure to install and configure Angular Material.

The library comes with the following form controls:

| Form control name | Description | | :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Button | Shows a button inside the form. Can be provided with a label and/or icon. You also provide a callback method for what happens when the button is clicked | | Button toggle | Based on the Angular Material component which shows a row of buttons, each holding a value (can be compared to radio buttons). It is possible to select one or multiple options | | Checkbox | Shows a checkbox, indicating a true or false value | | Input | Text based input using the HTML5 input element with Angular Material styling and animations. | | Radio group | Uses the mat-radio-group of Angular Material to show a group of radio buttons to select a single option | | Readonly | Shows the value of the control without the possibility to interact with it. | | Select | Uses the mat-select of Angular Material to show a list of options inside a dropdown. | | Textarea | The HTML5 <textarea> element with enchanced Angular Material styling and animations. |

Each control has a basic set of properties (see DynamicFormFieldConfig) that can be passed to the control's model. They also have a specific set of properties that only apply to the selected control.

Custom Form Controls

Other than the build-in form controls, it is possible to plug in you own custom controls. Start out with creating a custom form control component:

https://blog.angular-university.io/angular-custom-form-controls/

After that follow the following steps.

1. Create a model

First step is to create a model and interface for the custom control containing the control specific properties for the configuration definitions, extending the base interface/model from the library. Also, you need to create an (unique) name for the type of the model/.

For example if you're creating a control with a slider to select a value between 0 and 10:

Interface:

The interface extends the base interface DynamicFormFieldConfig and expects a generic type describing the possible value(s) of the field. In this case that would be a number or null value.

export interface SliderInputConfig extends DynamicFormFieldConfig<number | null> {
  min: number;
  max: number;
  step: number;
}

Model

The model is what is called when creating the form config (e.g. new SliderInput(sliderConfig)). The model contains the same properties defined in the configuration interface, and provides them with a value from the config or a default value.

Also, you need to create a field type token which we can later use to map the used model to the control component. In this case we created the token with the name DYNAMIC_FORM_FIELD_SLIDER with the value slider. The value HAS to be unique.

export const DYNAMIC_FORM_FIELD_SLIDER = 'slider';

export class SliderInput extends DynamicFormFieldValueModel<number | null> {
  public min: number;
  public max: number;
  public step: number;

  readonly type = DYNAMIC_FORM_FIELD_SLIDER;

  constructor(config: SliderInputConfig) {
    super(config);

    this.min = config.min ?? 0;
    this.max = config.max ?? 10;
    this.step = config.step ?? 1;
  }
}