@olafvv/ngx-dynamic-form 19.0.1 → 20.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +167 -204
  2. package/fesm2022/olafvv-ngx-dynamic-form.mjs +289 -357
  3. package/fesm2022/olafvv-ngx-dynamic-form.mjs.map +1 -1
  4. package/index.d.ts +561 -3
  5. package/package.json +5 -5
  6. package/lib/components/dynamic-form/dynamic-form.component.d.ts +0 -31
  7. package/lib/components/dynamic-form-field/dynamic-form-field.component.d.ts +0 -49
  8. package/lib/controls/button/dynamic-button.component.d.ts +0 -11
  9. package/lib/controls/button/dynamic-button.model.d.ts +0 -26
  10. package/lib/controls/button-toggles/dynamic-button-toggles.component.d.ts +0 -13
  11. package/lib/controls/button-toggles/dynamic-button-toggles.model.d.ts +0 -14
  12. package/lib/controls/checkbox/dynamic-checkbox.component.d.ts +0 -13
  13. package/lib/controls/checkbox/dynamic-checkbox.model.d.ts +0 -15
  14. package/lib/controls/controls.d.ts +0 -9
  15. package/lib/controls/datepicker/dynamic-datepicker.component.d.ts +0 -13
  16. package/lib/controls/datepicker/dynamic-datepicker.model.d.ts +0 -21
  17. package/lib/controls/input/dynamic-input.component.d.ts +0 -19
  18. package/lib/controls/input/dynamic-input.model.d.ts +0 -35
  19. package/lib/controls/radio-group/dynamic-radio-group.component.d.ts +0 -13
  20. package/lib/controls/radio-group/dynamic-radio-group.model.d.ts +0 -14
  21. package/lib/controls/readonly/dynamic-readonly.component.d.ts +0 -10
  22. package/lib/controls/readonly/dynamic-readonly.model.d.ts +0 -9
  23. package/lib/controls/select/dynamic-select.component.d.ts +0 -13
  24. package/lib/controls/select/dynamic-select.model.d.ts +0 -19
  25. package/lib/controls/textarea/dynamic-textarea.component.d.ts +0 -18
  26. package/lib/controls/textarea/dynamic-textarea.model.d.ts +0 -46
  27. package/lib/models/classes/dynamic-form-field-base.d.ts +0 -23
  28. package/lib/models/classes/dynamic-form-field-model.d.ts +0 -26
  29. package/lib/models/classes/dynamic-form-field-option-model.d.ts +0 -41
  30. package/lib/models/classes/dynamic-form-field-value-model.d.ts +0 -33
  31. package/lib/models/classes/dynamic-form-validators.d.ts +0 -48
  32. package/lib/models/constants/dynamic-relations.const.d.ts +0 -15
  33. package/lib/models/index.d.ts +0 -11
  34. package/lib/models/interfaces/dynamic-form-field-config.interface.d.ts +0 -68
  35. package/lib/models/interfaces/dynamic-form-field-event.interface.d.ts +0 -10
  36. package/lib/models/interfaces/dynamic-form-field-relation.interface.d.ts +0 -28
  37. package/lib/models/interfaces/dynamic-form-validator.interface.d.ts +0 -6
  38. package/lib/models/tokens/dynamic-form-field-map-fn.token.d.ts +0 -2
  39. package/lib/models/types/dynamic-form-config.type.d.ts +0 -2
  40. package/lib/models/types/related-form-controls.type.d.ts +0 -4
  41. package/lib/services/dynamic-form-relations.service.d.ts +0 -26
  42. package/lib/services/dynamic-form.service.d.ts +0 -46
  43. package/lib/services/dynamic-validations.service.d.ts +0 -20
  44. package/public-api.d.ts +0 -4
package/README.md CHANGED
@@ -1,66 +1,66 @@
1
- # NgxDynamicForm
1
+ # NgxDynamicForm 🚀
2
2
 
3
- 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](#custom-form-controls) form more information.
3
+ [![Angular Version](https://img.shields.io/badge/Angular-17.1%2B-red)](https://angular.io/)
4
+ [![Npm Version](https://img.shields.io/npm/v/@olafvv/ngx-dynamic-form)](https://www.npmjs.com/package/@olafvv/ngx-dynamic-form)
4
5
 
5
- ## Table of contents
6
+ **NgxDynamicForm** is a modern, strongly-typed, and highly performant library for dynamically generating Reactive Forms based on a JSON-like configuration model.
7
+
8
+ Leveraging cutting-edge Angular features like **Strict Typed Forms** and **Signal Inputs**, this library gives you top-tier developer experience without the boilerplate. Use our polished Angular Material built-in controls out of the box, or easily plug in your own custom fields!
9
+
10
+ ![NgxDynamicForm Showcase](https://via.placeholder.com/800x400.png?text=Interactive+Form+Animation+Here)
11
+
12
+ > _Tip: Replace the placeholder above with a GIF of the dynamic form in action!_
13
+
14
+ [![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](#) _(Link this to a live playground playground once deployed!)_
15
+
16
+ ---
17
+
18
+ ## 📖 Table of contents
6
19
 
7
20
  - [Getting Started](#getting-started)
8
- - [Usage](#usage)
21
+ - [Basic Usage (3 Steps)](#usage)
9
22
  - [Validators](#validators)
10
- - [Built-in validators](#built-in-validators)
11
- - [Custom validators](#custom-validators)
12
- - [Relations](#relations)
13
- - [Action type](#action-type)
14
- - [Conditions](#conditions)
15
- - [Operator](#operator)
16
- - [Custom Form Controls](#custom-form-controls)
23
+ - [Relations (Conditional Logic)](#relations)
24
+ - [Built-in Form Controls](#built-in-form-controls)
25
+ - [Creating Custom Form Controls](#custom-form-controls)
26
+
27
+ ---
17
28
 
18
29
  ## Getting started
19
30
 
20
- ##### 1. Make sure to install and configure [Angular Material](https://material.angular.io/guide/getting-started) if you want to use the built-in form controls
31
+ ##### 1. Configure Angular Material
21
32
 
22
- ##### 2. Install the library using npm:
33
+ Make sure to install and configure [Angular Material](https://material.angular.io/guide/getting-started) if you want to use the built-in form controls.
23
34
 
24
- ```
35
+ ##### 2. Install the library
36
+
37
+ ```bash
25
38
  npm i --save @olafvv/ngx-dynamic-form
26
39
  ```
27
40
 
28
- ## Usage
29
-
30
- ##### 1. Import the (standalone) component
41
+ ---
31
42
 
32
- ```ts
33
- import { DynamicFormComponent } from 'olafvv/ngx-dynamic-form';
34
-
35
- @NgModule({
36
- //...
37
- imports: [DynamicFormComponent]
38
- //...
39
- })
40
- export class AppModule {}
41
- ```
43
+ ## Usage
42
44
 
43
- **Or when using a standalone application/components:**
45
+ ##### 1. Import the standalone component
44
46
 
45
47
  ```ts
46
48
  import { DynamicFormComponent } from '@olafvv/ngx-dynamic-form';
47
49
 
48
50
  @Component({
49
51
  standalone: true,
50
- imports: [DynamicFormComponent]
52
+ imports: [DynamicFormComponent, ReactiveFormsModule]
51
53
  //...
52
54
  })
53
- export class AppComponent {
54
- //...
55
- }
55
+ export class AppComponent {}
56
56
  ```
57
57
 
58
58
  ##### 2. Define your form configuration
59
59
 
60
- 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](#form-layout) for more information.
60
+ Create the structured configuration for the form. This is a two-dimensional array where each array is a row in the form layout.
61
61
 
62
62
  ```ts
63
- import { DynamicInput, DynamicTextarea, DynamicFormValidators } from '@olafvv/ngx-dynamic-form';
63
+ import { DynamicInput, DynamicTextarea, DynamicFormConfig } from '@olafvv/ngx-dynamic-form';
64
64
 
65
65
  export const SAMPLE_FORM: DynamicFormConfig = [
66
66
  [
@@ -70,13 +70,6 @@ export const SAMPLE_FORM: DynamicFormConfig = [
70
70
  label: 'Name'
71
71
  })
72
72
  ],
73
- [
74
- new DynamicInput({
75
- name: 'email',
76
- inputType: 'email',
77
- label: 'Email address'
78
- })
79
- ],
80
73
  [
81
74
  new DynamicTextarea({
82
75
  name: 'message',
@@ -88,49 +81,53 @@ export const SAMPLE_FORM: DynamicFormConfig = [
88
81
  ];
89
82
  ```
90
83
 
91
- ##### 3. Create a FormGroup
84
+ ##### 3. Create the Form & Render it!
92
85
 
93
- This library provides the service `DynamicFormService` which you can use to create a FormGroup based on the created form configuration.
86
+ Use the library's `DynamicFormService` to generate a strict, reactive `FormGroup` and pass tis `FormGroup` and the configuration to the `<dynamic-form>` component inside the template.
94
87
 
95
88
  ```ts
96
- import { SAMPLE_FORM } from './sample-form.ts';
97
- import { DynamicFormService } from '@olafvv/ngx-dynamic-form;
89
+ import { Component, inject } from '@angular/core';
90
+ import { DynamicFormService, DynamicFormConfig } from '@olafvv/ngx-dynamic-form';
91
+ import { SAMPLE_FORM } from './sample-form';
98
92
 
99
93
  @Component({
100
- //...
94
+ standalone: true,
95
+ imports: [DynamicFormComponent],
96
+ template: `
97
+ <form [formGroup]="formGroup">
98
+ <!-- 🚀 Render the dynamic form dynamically! -->
99
+ <dynamic-form
100
+ [group]="formGroup"
101
+ [formConfig]="formConfig" />
102
+ </form>
103
+ `
101
104
  })
102
- export class AppComponent {
103
- sampleFormConfig: DynamicFormConfig = SAMPLE_FORM;
104
- sampleFormGroup: FormGroup<SampleFormModel> = this.dynamicFormService.createFormGroup(this.sampleFormConfig);
105
+ export class MyFormComponent {
106
+ private dynamicFormService = inject(DynamicFormService);
105
107
 
106
- constructor(private dynamicFormService: DynamicFormService) {}
108
+ formConfig: DynamicFormConfig = SAMPLE_FORM;
109
+ formGroup = this.dynamicFormService.createFormGroup(this.formConfig);
107
110
  }
108
111
  ```
109
112
 
110
- ##### 4. Add the `dynamic-form` inside the template
111
-
112
- 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:
113
-
114
- ```html
115
- <form [formGroup]="sampleFormGroup">
116
- <dynamic-form [group]="sampleFormGroup" [formConfig]="sampleFormConfig">
117
- </form>
118
- ```
113
+ ---
119
114
 
120
115
  ## Validators
121
116
 
122
- This library comes with a set of built-in validators, based on the [Angular Validators](https://angular.dev/api/forms/Validators). All provided validators are static methods inside the class `DynamicFormValidators`, each returning a `DynamicFormValidator` (e.g. `DynamicFormValidators.required()`).
123
-
124
- To use the validators, pass them inside the validators array of the field configuration:
117
+ This library comes with a set of built-in formatters mapped seamlessly to standard [Angular Validators](https://angular.dev/api/forms/Validators). They are provided via static methods inside `DynamicFormValidators` (e.g. `DynamicFormValidators.required()`).
125
118
 
126
119
  ```ts
127
120
  import { DynamicFormValidators } from '@olafvv/ngx-dynamic-form';
128
121
 
129
122
  export const SAMPLE_FORM = [
130
123
  [
131
- new DynamicFormInput({
132
- //..
133
- validators: [DynamicFormValidators.required('Custom error message')]
124
+ new DynamicInput({
125
+ name: 'email',
126
+ inputType: 'email',
127
+ validators: [
128
+ DynamicFormValidators.required('Email address is required!'),
129
+ DynamicFormValidators.email('Please provide a valid email')
130
+ ]
134
131
  })
135
132
  ]
136
133
  ];
@@ -163,115 +160,41 @@ class DynamicFormValidators {
163
160
 
164
161
  #### Custom Validators
165
162
 
166
- 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.
167
-
168
- Read more about creating custom Angular validators on the following page:
169
-
170
- > https://blog.angular-university.io/angular-custom-validators/
171
-
172
- E.g. a validator to require a minimum time:
163
+ You can easily provide custom validation logic by passing an object of type `DynamicFormValidator` into the `validators` property.
173
164
 
174
165
  ```ts
175
- function minTimeValidatorFn(minTime: string): ValidatorFn {
176
- return (control: AbstractControl): ValidationErrors | null => {
177
- const inputTime = control.value as string;
178
-
179
- if (!inputTime) return null;
180
-
181
- const minTimeObj = new Date(`2000-01-01T${minTime}`);
182
- const inputTimeObj = new Date(`2000-01-01T${inputTime}`);
183
-
184
- return inputTimeObj >= minTimeObj ? null : { minTime: true };
185
- };
186
- }
187
-
188
166
  export const minTimeValidator: (minTime: string, msg?: string) => DynamicFormValidator = (minTime: string, msg?: string) => ({
189
167
  name: 'minTime',
190
- validator: minTimeValidatorFn(minTime),
191
- message: msg ?? `Minimale tijd is ${minTime}`
168
+ validator: minTimeValidatorFn(minTime), // Your custom function returning an Angular ValidationErrors object
169
+ message: msg ?? `Minimum time allowed is ${minTime}`
192
170
  });
193
171
  ```
194
172
 
195
- ```ts
196
- import { minTimeValidator } from './min-time-validator.ts';
197
-
198
- //..
199
-
200
- const formConfig: DynamicFormConfig = [
201
- [
202
- new DynamicInput({
203
- name: 'time',
204
- inputType: 'time',
205
- validators: [minTimeValidator('11:00')]
206
- })
207
- ]
208
- ];
209
- ```
173
+ ---
210
174
 
211
175
  ## Relations
212
176
 
213
- 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.
177
+ Sometimes you want to create interconnected logic between fields (e.g., hiding a passport number input unless the document type is set to "Passport"). NgxDynamicForm handles conditionally reactive states natively using **Relations**.
178
+
179
+ Each relation defines an Action Type, a source condition, and an operator.
214
180
 
215
- 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.
181
+ ##### DynamicFormFieldRelation type
216
182
 
217
183
  ```ts
218
- interface DynamicFormFieldRelation {
184
+ type DynamicFormFieldRelation {
219
185
  actionType: RelationActionType;
220
186
  conditions: RelationCondition[];
221
187
  operator?: RelationOperator;
222
188
  }
223
189
  ```
224
190
 
225
- ##### Action type
226
-
227
- 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:
191
+ ##### Action Types
228
192
 
229
- - Disable/Enable
230
- - Visible/Hidden
231
- - Required/Optional
193
+ - `DISABLED` / `ENABLED`
194
+ - `HIDDEN` / `VISIBLE`
195
+ - `REQUIRED` / `OPTIONAL`
232
196
 
233
- To set the type you have to use one of the provided enums:
234
-
235
- ```ts
236
- enum RelationActionType {
237
- DISABLED = 'DISABLED',
238
- ENABLED = 'ENABLED',
239
- HIDDEN = 'HIDDEN',
240
- VISIBLE = 'VISIBLE',
241
- REQUIRED = 'REQUIRED',
242
- OPTIONAL = 'OPTIONAL'
243
- }
244
- ```
245
-
246
- ##### Conditions
247
-
248
- 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:
249
-
250
- ```ts
251
- interface RelationCondition {
252
- // The name of the field this field is related to
253
- fieldName: string;
254
- // A method which has to return a boolean. Returning true means the condition is met
255
- value: (val: any) => boolean;
256
- }
257
- ```
258
-
259
- ##### Operator
260
-
261
- 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.
262
-
263
- ```ts
264
- enum RelationOperator {
265
- // All conditions have to equal true
266
- AND = 'AND',
267
- // On of the conditions have to equal true
268
- OR = 'OR'
269
- }
270
- ```
271
-
272
- ##### Example
273
-
274
- 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':
197
+ ##### Example: Conditional Visibility
275
198
 
276
199
  ```ts
277
200
  const formConfig = [
@@ -280,21 +203,22 @@ const formConfig = [
280
203
  name: 'documentType',
281
204
  label: 'Document type',
282
205
  options: [
283
- { label: 'Passport', value: 'passport' }
284
- //..
206
+ { label: 'Passport', value: 'passport' },
207
+ { label: 'ID Card', value: 'id' }
285
208
  ]
286
209
  })
287
- ][
288
- new DymamicInput({
210
+ ],
211
+ [
212
+ new DynamicInput({
289
213
  name: 'passportNumber',
290
214
  label: 'Passport number',
291
215
  relations: [
292
216
  {
293
- actionType: RelationActionType.VISIBLE,
217
+ actionType: RelationActionType.VISIBLE, // Make this field visible...
294
218
  conditions: [
295
219
  {
296
- fieldName: 'documentType',
297
- value: (val: string) => val === 'passport'
220
+ fieldName: 'documentType', // ...when 'documentType' field...
221
+ value: (val: string) => val === 'passport' // ...equals 'passport'
298
222
  }
299
223
  ]
300
224
  }
@@ -304,75 +228,114 @@ const formConfig = [
304
228
  ];
305
229
  ```
306
230
 
307
- ## Built-in form controls
231
+ ---
308
232
 
309
- 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](https://material.angular.io).
233
+ ## Built-in form controls
310
234
 
311
- The library comes with the following form controls:
235
+ The library comes with a battle-tested set of built-in form controls utilizing **Angular Material**.
312
236
 
313
- | Form control name | Description |
314
- | :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
315
- | 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 |
316
- | 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 |
317
- | Checkbox | Shows a checkbox, indicating a true or false value |
318
- | Input | Text based input using the HTML5 input element with Angular Material styling and animations. |
319
- | Radio group | Uses the `mat-radio-group` of Angular Material to show a group of radio buttons to select a single option |
320
- | Readonly | Shows the value of the control without the possibility to interact with it. |
321
- | Select | Uses the `mat-select` of Angular Material to show a list of options inside a dropdown. |
322
- | Textarea | The HTML5 `<textarea>` element with enchanced Angular Material styling and animations. |
237
+ | Control Name | Description |
238
+ | :---------------- | :------------------------------------------------------------------------------------ |
239
+ | **Button** | Highly-customizable actionable button with a click callback. |
240
+ | **Button toggle** | Horizontal toggle groupings ideal for single or multi-select radio behavior. |
241
+ | **Checkbox** | Standard binary state checkbox. |
242
+ | **Input** | Standard HTML5 inputs with embedded floating labels, validation hints, and matchings. |
243
+ | **Radio group** | Vertically or horizontally stacked radio selectors. |
244
+ | **Readonly** | Presentational un-editable field representation. |
245
+ | **Select** | Dropdown menu powered by `mat-select` or native `<select>`. |
246
+ | **Textarea** | Auto-resizing text area input. |
323
247
 
324
- 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.
248
+ ---
325
249
 
326
250
  ## Custom Form Controls
327
251
 
328
- 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:
329
-
330
- > https://blog.angular-university.io/angular-custom-form-controls/
331
-
332
- After that follow the following steps.
333
-
334
- #### 1. Create a model
335
-
336
- 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.
337
- Also, you need to create an (unique) name for the type of the model/.
338
-
339
- For example if you're creating a control with a slider to select a value between 0 and 10:
252
+ NgxDynamicForm was built with modern extensibility in mind. Creating a brand new dynamic control is easy using the generic `DynamicFormFieldBase<M>` abstraction.
340
253
 
341
- ##### Interface:
254
+ ### 1. Create a Model & Options Type
342
255
 
343
- 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.
256
+ First, define a type for your specific options and a model class that Angular will parse.
344
257
 
345
258
  ```typescript
346
- export interface SliderInputConfig extends DynamicFormFieldConfig<number | null> {
347
- min: number;
348
- max: number;
349
- step: number;
350
- }
351
- ```
352
-
353
- #### Model
354
-
355
- The model is what is called when creating the form config (e.g. `new SliderInput(sliderConfig)`).
356
- The model contains the same properties defined in the configuration interface, and provides them with a value from the config or a default value.
259
+ import { DynamicFormFieldValueConfig, DynamicFormFieldValueModel } from '@olafvv/ngx-dynamic-form';
357
260
 
358
- 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.
261
+ export type SliderInputConfig = DynamicFormFieldValueConfig<number | null> & {
262
+ min?: number;
263
+ max?: number;
264
+ step?: number;
265
+ };
359
266
 
360
- ```typescript
361
267
  export const DYNAMIC_FORM_FIELD_SLIDER = 'slider';
362
268
 
363
269
  export class SliderInput extends DynamicFormFieldValueModel<number | null> {
364
270
  public min: number;
365
271
  public max: number;
366
272
  public step: number;
367
-
368
- readonly type = DYNAMIC_FORM_FIELD_SLIDER;
273
+ public readonly type = DYNAMIC_FORM_FIELD_SLIDER;
369
274
 
370
275
  constructor(config: SliderInputConfig) {
371
276
  super(config);
372
-
373
277
  this.min = config.min ?? 0;
374
278
  this.max = config.max ?? 10;
375
279
  this.step = config.step ?? 1;
376
280
  }
377
281
  }
378
282
  ```
283
+
284
+ ### 2. Create the Strongly-Typed Component
285
+
286
+ Because this library uses **Angular 17+ Signal Inputs**, your custom component should extend `DynamicFormFieldBase` natively.
287
+
288
+ **`slider.component.ts`**:
289
+
290
+ ```typescript
291
+ import { Component, input } from '@angular/core';
292
+ import { FormGroup, ReactiveFormsModule } from '@angular/forms';
293
+ import { DynamicFormFieldBase } from '@olafvv/ngx-dynamic-form';
294
+ import { SliderInput } from './slider-input.model';
295
+
296
+ @Component({
297
+ standalone: true,
298
+ selector: 'app-custom-slider',
299
+ imports: [ReactiveFormsModule],
300
+ template: `
301
+ <div
302
+ class="slider-wrapper"
303
+ [formGroup]="group()">
304
+ <label>{{ model().label }}</label>
305
+
306
+ <!-- Your custom markup here -->
307
+ <input
308
+ type="range"
309
+ [min]="model().min"
310
+ [max]="model().max"
311
+ [step]="model().step"
312
+ [formControlName]="model().name" />
313
+ </div>
314
+ `
315
+ })
316
+ // Notice how passing `SliderInput` strictly types the generic base class!
317
+ export class SliderComponent extends DynamicFormFieldBase<SliderInput> {
318
+ public model = input.required<SliderInput>();
319
+ public group = input.required<FormGroup>();
320
+ }
321
+ ```
322
+
323
+ ### 3. Registering the Control
324
+
325
+ Finally, tell the `DynamicFormService` how to connect the `SliderInput` model (`slider`) to the `SliderComponent` rendering engine via dependency injection using `DYNAMIC_FORM_CONTROL_MAP`.
326
+
327
+ ```ts
328
+ @NgModule({
329
+ ...
330
+ providers: [
331
+ {
332
+ provide: DYNAMIC_FORM_FIELD_MAP,
333
+ useValue: {
334
+ [DYNAMIC_FORM_FIELD_SLIDER]: SliderComponent
335
+ }
336
+ }
337
+ ]
338
+ })
339
+ export class AppModule {}
340
+
341
+ ```