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

@eqproject/eqp-form

v21.0.1

Published

Dynamic forms directive - Angular Material based

Readme

Eqp Form Component

Table of contents


Required

  • [X] Angular Material installed and imported
  • [X] @eqproject/eqp-common package installed (used for models and utilities)
  • [X] @eqproject/eqp-select installed (required for Enum and Cvl field types)
  • [X] @eqproject/eqp-lookup installed (required for Lookup field type)
  • [X] @eqproject/eqp-datetimerangepicker installed (required for Date, DateTime and DateRange field types)

Getting started

Step 1: Install eqp-form:

NPM

npm install --save @eqproject/eqp-form

Step 2: Import EqpFormModule in your app module

import { EqpFormModule } from '@eqproject/eqp-form';

@NgModule({
  declarations: [AppComponent],
  imports: [EqpFormModule],
  bootstrap: [AppComponent]
})
export class AppModule {}

Step 3: Use in your component

Define selector in HTML:

<eqp-form
  [fields]="fields"
  [record]="record"
  [disabledForm]="false"
  [resetFormLabel]="'Annulla'"
  [submitFormLabel]="'Salva'"
  (valueChanged)="onValueChanged($event)"
  (submitEvent)="onFormSubmit($event)">
</eqp-form>

Define the form configuration in your component:

import { FormField, FormFieldType } from '@eqproject/eqp-common';

fields: FormField[] = [
  {
    key: 'name',
    display: 'Name',
    formFieldType: FormFieldType.Text,
    required: true,
    orderPosition: 1
  },
  {
    key: 'age',
    display: 'Age',
    formFieldType: FormFieldType.Number,
    validationProperties: {
      Valid: (value: number) => value >= 0,
      HintLabel: 'Age must be positive'
    },
    orderPosition: 2
  },
  {
    key: 'isActive',
    display: 'Active',
    formFieldType: FormFieldType.Boolean,
    value: true,
    orderPosition: 3
  }
];

record = {
  name: 'Mario Rossi',
  age: 30,
  isActive: true
};

onValueChanged(value: any): void {
  console.log('Value changed:', value);
}

onFormSubmit(formData: any): void {
  console.log('Form submitted:', formData);
}

Use Cases

1. Basic Form

Easily create a simple dynamic form using a list of FormField objects.

<eqp-form [fields]="fields" (submitEvent)="onSubmit($event)"></eqp-form>

2. Disabled Form

Disable the entire form dynamically:

<eqp-form [fields]="fields" [disabledForm]="true"></eqp-form>

3. Dynamic Record Binding

You can update the record at runtime:

this.record = { name: 'Luigi Bianchi', age: 25, isActive: false };

The form will automatically patch values via ngOnChanges whenever the record input reference changes.


4. Enum (CVL based on enum) Field

Use FormFieldType.Enum to render an eqp-select driven by a TypeScript enum. Configure behaviour through the selectObject property of FormField.

this.fields = [
  {
    key: 'gender',
    display: 'Sesso',
    formFieldType: FormFieldType.Enum,
    enumModel: GenderEnum,
    selectObject: {
      isEnumMultiSelect: false,
      isEnumSearchable: true,
      enumSearchText: 'Cerca...',
      showEnumCancelButton: true
    },
    orderPosition: 1
  }
];

5. CVL (array-based select) Field

Use FormFieldType.Cvl to render an eqp-select driven by an arbitrary array. Configure the data source and behaviour through selectObject.

this.fields = [
  {
    key: 'categoryId',
    display: 'Categoria',
    formFieldType: FormFieldType.Cvl,
    selectObject: {
      arrayData: [{ ID: 1, Label: 'Categoria A' }, { ID: 2, Label: 'Categoria B' }],
      arrayKeyProperty: 'ID',       // default: 'ID'
      arrayValueProperty: 'Label',  // default: 'Label'
      isEnumMultiSelect: false,
      isEnumSearchable: true,
      showEnumCancelButton: true,
      isRequired: false
    },
    orderPosition: 1
  }
];

6. Lookup Field

Use FormFieldType.Lookup to embed a full eqp-lookup inside the form. The lookup widget handles both HTTP-driven and static-item scenarios. Configure via the lookupObject property.

this.fields = [
  {
    key: 'userId',
    display: 'Utente',
    formFieldType: FormFieldType.Lookup,
    lookupObject: {
      fullUrlHttpCall: '/api/users/lookup',
      bindKey: 'ID',         // default: 'ID'
      bindLabel: 'Label',    // default: 'Label'
      isMultiple: false,
      isSearchable: true,
      isClearable: true,
      isRequired: false,
      bindCompleteObject: true   // default: true — binds the full selected object
    },
    orderPosition: 1
  }
];

If lookupObject is not defined when the field type is Lookup, the component will throw an error: Missing lookupObject on field: <key>.


7. Date / DateTime / DateRange Fields

All date-oriented field types delegate rendering to eqp-datetimerangepicker internally. The three variants are selected automatically based on formFieldType.

this.fields = [
  {
    key: 'birthDate',
    display: 'Data di nascita',
    formFieldType: FormFieldType.Date,
    orderPosition: 1
  },
  {
    key: 'appointmentDateTime',
    display: 'Appuntamento',
    formFieldType: FormFieldType.DateTime,
    orderPosition: 2
  },
  {
    key: 'period',
    display: 'Periodo',
    formFieldType: FormFieldType.DateRange,
    orderPosition: 3
  }
];

When FormFieldType.DateRange is used, the component creates two separate FormControl entries in the FormGroup: one named key + "_START" and one named key + "_END". If a default value is provided via record, the object is expected to have the shape { from: Date, to: Date }. The submitted form value will therefore include both period_START and period_END keys.


8. External Template Field

Use FormFieldType.ExternalTemplate to inject a fully custom control into a form slot. You define the template in the parent component and pass it as externalTemplate on the FormField. The template receives three context variables: form (the parent FormGroup), field (the current FormField), and control (the resolved AbstractControl for this field).

<!-- In the parent component template -->
<ng-template #myCustomField let-form="form" let-field="field" let-control="control">
  <mat-form-field>
    <mat-label>{{ field.display }}</mat-label>
    <input matInput [formControl]="control" />
    @if (control?.invalid && control?.touched) {
      <mat-error>{{ field.validationProperties?.HintLabel }}</mat-error>
    }
  </mat-form-field>
</ng-template>

<eqp-form [fields]="fields" (submitEvent)="onSubmit($event)"></eqp-form>
@ViewChild('myCustomField', { static: true }) myCustomField: TemplateRef<any>;

ngOnInit(): void {
  this.fields = [
    {
      key: 'customField',
      display: 'Campo personalizzato',
      formFieldType: FormFieldType.ExternalTemplate,
      externalTemplate: this.myCustomField,
      orderPosition: 1
    }
  ];
}

9. Field with Tooltip

Any field type supports an optional tooltip property. When set, a mat-hint is shown below the control with the tooltip text.

this.fields = [
  {
    key: 'taxCode',
    display: 'Codice Fiscale',
    formFieldType: FormFieldType.Text,
    placeholder: 'Es. RSSMRA80A01H501U',
    tooltip: {
      tooltipText: 'Il codice fiscale deve essere composto da 16 caratteri alfanumerici.'
    },
    orderPosition: 1
  }
];

10. Boolean with custom label position

Boolean fields render as a mat-slide-toggle. The label position can be controlled via the booleanLabelPosition property using the BoolLabelPosition enum from @eqproject/eqp-common.

import { BoolLabelPosition } from '@eqproject/eqp-common';

this.fields = [
  {
    key: 'isActive',
    display: 'Attivo',
    formFieldType: FormFieldType.Boolean,
    value: false,
    booleanLabelPosition: BoolLabelPosition.Before, // label on the left of the toggle
    orderPosition: 1
  }
];

Boolean fields always default to false if no value is provided via record or the value property — they are never initialized as null.


FormField Configuration

The FormField model (imported from @eqproject/eqp-common) defines how each field in the form is generated.

| Property | Type | Required | Description | | -------------------- | ------------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | key | string | ✅ | Unique name of the field (also used as form control name). | | display | string | ✅ | Label to display in the form. | | formFieldType | FormFieldType | ✅ | Type of field to render. See the FormFieldType enum table below for all supported values. | | value | any | ❌ | Default value if record is not provided. | | showInForm | boolean | ❌ | If false, field is hidden from the form and its control is removed from the FormGroup. Default: true. | | disabled | boolean | ❌ | Whether the field is disabled. | | required | boolean | ❌ | Whether the field is mandatory. Automatically adds Validators.required and sets HintLabel to "Campo obbligatorio" if no custom validationProperties are provided. | | orderPosition | number | ❌ | Defines visual ordering of fields. Fields with null orderPosition are placed at the end. | | placeholder | string | ❌ | Placeholder text shown inside Text and Number input fields. | | tooltip | { tooltipText: string } | ❌ | If defined, shows a mat-hint below the control with the given text. Supported by Text, Number and Boolean field types. | | booleanLabelPosition | BoolLabelPosition | ❌ | Controls whether the label of a Boolean (mat-slide-toggle) appears before or after the toggle. Imported from @eqproject/eqp-common. | | validationProperties | { Valid: Function; HintLabel?: string } | ❌ | Allows defining custom validation logic and related error message. | | dependentFieldKey | string | ❌ | Defines another field key this one depends on. | | dependentValidation | (value: any) => boolean | ❌ | Function that determines if this field should be visible/enabled depending on the dependent field value. When it returns false, the control is removed from the FormGroup. | | enumModel | any | ❌ | The TypeScript enum to use as the data source when formFieldType is FormFieldType.Enum. Passed directly to eqp-select. | | selectObject | FormFieldSelectConfig | ❌ | Configuration object for Enum and Cvl field types. Must be provided for Cvl; optional for Enum. Throws an error if missing for Cvl. See details below. | | lookupObject | FormFieldLookupConfig | ❌ | Configuration object for Lookup field type. Must be defined when formFieldType is FormFieldType.Lookup. Throws an error if missing. | | externalTemplate | TemplateRef<any> | ❌ | The ng-template to render when formFieldType is FormFieldType.ExternalTemplate. The template receives { form, field, control } as context variables. |

FormFieldSelectConfig properties (used by Enum and Cvl types)

| Property | Type | Default | Description | | ----------------------- | ----------------------- | -------------------- | ----------------------------------------------------------------------------------------------------- | | enumData | any | - | Enum type to use as data source (Cvl only, for enum-backed arrays). | | enumDataToExclude | any | - | Enum values to exclude from the list. | | arrayData | any[] | - | Static array of items to populate the select (Cvl only). | | arrayKeyProperty | string | 'ID' | Property name to use as the bound key from arrayData items. | | arrayValueProperty | string | 'Label' | Property name to display in the dropdown from arrayData items. | | isEnumMultiSelect | boolean | false | Enables multi-selection. | | isEnumSearchable | boolean | false | Shows a search box inside the dropdown. | | showEnumCancelButton | boolean | true | Shows a clear button to reset the selection. | | enumSearchText | string | - | Placeholder text for the search box. | | isRequired | boolean | false | Marks the select as required. | | isMultiLanguage | boolean | false | Enables multi-language label rendering via ngx-translate. | | multilanguagePrefixKey | string | - | Translation key prefix for multi-language mode. | | isAlphabeticalOrderable | boolean | false | Sorts items alphabetically. | | isReadonly | boolean | false | Makes the select read-only. | | dropdownPosition | string | 'auto' | Dropdown position: 'auto', 'top', 'bottom'. | | selectOnTab | boolean | true | Selects the highlighted item when Tab is pressed. | | selectAll | boolean | false | Shows a "Select all" option for multi-select. | | selectAllText | string | 'Seleziona tutto' | Label for the "Select all" option. | | clearAllText | string | 'Elimina' | Label for the clear-all button in multi-select. | | appendToInput | string | 'body' | CSS selector for the element to append the dropdown to. | | customOption | TemplateRef<any> | - | Custom template for rendering each dropdown option. | | customLabel | TemplateRef<any> | - | Custom template for rendering the selected label. |

FormFieldLookupConfig properties (used by Lookup type)

| Property | Type | Default | Description | | -------------------------------------------- | ------------------ | -------------------------- | ----------------------------------------------------------------------------------------------------- | | fullUrlHttpCall | string | - | Full URL for the HTTP data source. | | lookupEntityType | any | - | Entity type for the lookup (used with eqp-lookup's entity-based data fetching). | | bindKey | string | 'ID' | Property name to use as the bound key. | | bindLabel | string | 'Label' | Property name to display in the dropdown. | | items | any[] | - | Static array of items (alternative to HTTP call). | | initialItems | any[] | - | Pre-loaded items displayed before any search. | | isMultiple | boolean | false | Enables multi-selection. | | isSearchable | boolean | true | Shows a search box. | | isClearable | boolean | true | Shows a clear button. | | isVirtualScroll | boolean | false | Enables virtual scrolling for large datasets. | | isReadonly | boolean | false | Makes the lookup read-only. | | isRequired | boolean | false | Marks the lookup as required. | | isEditable | boolean | false | Shows an edit button next to the selected item. | | isMultiline | boolean | false | Enables multiline display for selected values. | | bindCompleteObject | boolean | true | If true, binds the full selected object to the form control instead of just the key value. | | notFoundText | string | 'Nessun risultato trovato' | Text shown when no results match. | | addButtonText | string | 'Crea nuovo' | Label for the add-new button. | | editButtonText | string | 'Modifica' | Label for the edit button. | | appendToInput | string | 'body' | CSS selector for the element to append the dropdown to. | | dropdownPosition | string | 'auto' | Dropdown position. | | selectOnTab | boolean | false | Selects the highlighted item when Tab is pressed. | | selectAll | boolean | false | Shows a "Select all" option. | | sortList | boolean | false | Sorts the dropdown list alphabetically. | | dataFilter | any | - | Simple filter object applied to HTTP requests. | | complexDataFilter | any | - | Complex LINQ-style filter applied to HTTP requests. | | manipulateDataFn | Function | - | Function to transform the data array before rendering. | | compareFunction | Function | - | Custom equality function for item matching. | | customOption | TemplateRef<any> | - | Custom template for rendering each dropdown option. | | customLabel | TemplateRef<any> | - | Custom template for rendering the selected label. | | disableReloadOnLookupAddingCompleteParent | boolean | false | Disables automatic list reload when the add-new dialog closes. | | showOptionTooltip | boolean | false | Shows a tooltip on each option. | | isSearchWhileComposing | boolean | false | Triggers search while the user is composing (IME input). | | ngModelInput | any | - | Two-way binding value when using ngModel instead of reactive form. | | ngModelOptions | any | - | Options object passed to ngModel (e.g. { standalone: true }). | | groupBy | any | - | Property or function for grouping dropdown options. | | groupByProperty | string | - | Property name used to group items. | | selectableGroup | boolean | false | Allows selecting a group header as a value. | | selectableGroupAsModel | boolean | false | Binds the group model when a group header is selected. |


FormFieldType enum

| Value | Rendered Control | Notes | | ------------------ | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- | | Text | <input matInput type="text"> | Supports placeholder and tooltip. | | Number | <input matInput type="number"> | Supports placeholder and tooltip. | | Boolean | mat-slide-toggle | Always initializes to false if no value is given. Supports tooltip and booleanLabelPosition. | | Date | eqp-datetimerangepicker in DATE mode | Outputs a Moment value. | | DateTime | eqp-datetimerangepicker in DATETIME mode | Outputs a Moment value. | | DateRange | eqp-datetimerangepicker in DATE_RANGE mode | Creates two FormControls: key_START and key_END. Record value must be { from: Date, to: Date }. | | Enum | eqp-select driven by a TypeScript enum (enumModel) | Requires enumModel on the FormField. Optionally configured via selectObject. | | Cvl | eqp-select driven by selectObject.arrayData | Requires selectObject. Throws if missing. arrayKeyProperty defaults to 'ID', arrayValueProperty to 'Label'. | | Lookup | eqp-lookup | Requires lookupObject. Throws if missing. bindKey defaults to 'ID', bindLabel to 'Label'. | | ExternalTemplate | Custom ng-template | Requires externalTemplate on the FormField. Context: { form, field, control }. |


Dynamic Field Dependencies

You can define conditional visibility or validation between fields using dependentFieldKey and dependentValidation.

Example:

fields: FormField[] = [
  {
    key: 'hasVehicle',
    display: 'Do you own a vehicle?',
    formFieldType: FormFieldType.Boolean
  },
  {
    key: 'vehicleModel',
    display: 'Vehicle Model',
    formFieldType: FormFieldType.Text,
    dependentFieldKey: 'hasVehicle',
    dependentValidation: (value) => value === true
  }
];

In this example, the vehicleModel field will only appear when hasVehicle is checked. When dependentValidation returns false, the control is removed from the FormGroup entirely — it will not appear in the submitted form data. When it returns true, a new control is added back with the field's initial value.

The dependency subscription is set up once during ngOnInit, so dependentFieldKey must reference a field that already exists in the fields array at initialization time.


API

Inputs

| Input | Type | Default | Required | Description | | ----------------- | --------------- | ----------- | -------- | --------------------------------------------------------- | | [fields] | FormField[] | [] | ✅ | Array of form field configurations. Sorted by orderPosition (nulls last) on init. | | [record] | any | null | ❌ | Object containing the default values for the form fields. When this reference changes after init, form.patchValue() is called automatically. | | [disabledForm] | boolean | false | ❌ | Disable all controls in the form. | | [resetFormLabel] | string | 'Reset' | ❌ | Label for the reset button. | | [submitFormLabel] | string | 'Salva' | ❌ | Label for the submit button. |


Outputs

| Output | Event Arguments | Required | Description | | -------------- | --------------- | -------- | ----------------------------------------------------------------------- | | (valueChanged) | any | ❌ | Emitted whenever a child field changes its value. The event payload shape depends on the field type: text and number emit { key, value }, boolean emits the raw boolean value, date fields emit { key, value: Moment }, select and lookup fields emit the full selected item. | | (submitEvent) | object | ✅ | Emitted when the form is submitted and valid; contains form.getRawValue() (includes disabled controls). Not emitted if any visible field fails validation — all controls are marked as touched to display error messages. |


Public Methods (can be accessed via @ViewChild)

| Method | Description | Returns | | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | | onSubmit() | Programmatically triggers form validation. Marks all visible controls as touched to display error messages. Emits submitEvent with form.getRawValue() if valid. | void | | resetForm() | Resets each visible field individually. Boolean fields are explicitly set back to false after reset (they are never left as null). Does not call form.reset(). | void |


Notes on behavior

Field ordering

The fields array is sorted by orderPosition during ngOnInit. Fields with a null or undefined orderPosition are placed at the end. The sorting is stable — two fields with the same position retain their original relative order.

Form validation and submit

Calling onSubmit() (whether by clicking the submit button or programmatically via @ViewChild) first marks all visible controls as touched. This causes validation error messages to appear on screen. If the entire form is valid, submitEvent is emitted with form.getRawValue(), which includes the values of disabled controls as well as enabled ones.

Record auto-patching

After the form is initialized, any change to the record input binding triggers an automatic form.patchValue(record) call via ngOnChanges. Only the values that correspond to existing form controls are patched; extra properties on record are silently ignored.

BaseField auto-conversion

If the fields array is composed of BaseField objects rather than FormField objects (a pattern used when fields come from generic eqp-common utilities), the component automatically converts them via EqpCommonService.convertAs<FormField>() before building the form.


Example: Programmatic Form Submit

@ViewChild(EqpFormComponent) eqpForm: EqpFormComponent;

submitProgrammatically() {
  this.eqpForm.onSubmit(); // triggers validation and submit event
}

Example: Reset Form

<button mat-button color="warn" (click)="eqpForm.resetForm()">Reset</button>

Credits

This library has been developed by EqProject SRL

📧 [email protected]

🌐 https://www.eqproject.it