@bcweed/dynamic-form-lib 0.0.1 → 0.0.3
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.
- package/README.md +19 -15
- package/fesm2022/bcweed-dynamic-form-lib.mjs +938 -0
- package/fesm2022/bcweed-dynamic-form-lib.mjs.map +1 -0
- package/index.d.ts +254 -0
- package/package.json +37 -65
- package/.editorconfig +0 -17
- package/.postcssrc.json +0 -5
- package/.vscode/extensions.json +0 -4
- package/.vscode/launch.json +0 -20
- package/.vscode/tasks.json +0 -42
- package/AngularDynamicFormLibrary.esproj +0 -13
- package/CHANGELOG.md +0 -16
- package/angular.json +0 -169
- package/aspnetcore-https.js +0 -37
- package/karma.conf.js +0 -44
- package/obj/Debug/AngularDynamicFormLibrary.esproj.CoreCompileInputs.cache +0 -0
- package/obj/Debug/AngularDynamicFormLibrary.esproj.FileListAbsolute.txt +0 -1
- package/obj/Debug/package.g.props +0 -56
- package/postcss.config.js +0 -6
- package/projects/dynamic-form-lib/.postcssrc.json +0 -5
- package/projects/dynamic-form-lib/README.md +0 -63
- package/projects/dynamic-form-lib/ng-package.json +0 -10
- package/projects/dynamic-form-lib/package.json +0 -27
- package/projects/dynamic-form-lib/src/lib/README.md +0 -424
- package/projects/dynamic-form-lib/src/lib/SUMMARY.md +0 -159
- package/projects/dynamic-form-lib/src/lib/directives/dynamic-ref-directive.ts +0 -13
- package/projects/dynamic-form-lib/src/lib/dynamic-form-demo/dynamic-form-demo.component.html +0 -75
- package/projects/dynamic-form-lib/src/lib/dynamic-form-demo/dynamic-form-demo.component.scss +0 -127
- package/projects/dynamic-form-lib/src/lib/dynamic-form-demo/dynamic-form-demo.component.ts +0 -50
- package/projects/dynamic-form-lib/src/lib/dynamic-form-field/dynamic-form-field.component.html +0 -234
- package/projects/dynamic-form-lib/src/lib/dynamic-form-field/dynamic-form-field.component.scss +0 -315
- package/projects/dynamic-form-lib/src/lib/dynamic-form-field/dynamic-form-field.component.ts +0 -219
- package/projects/dynamic-form-lib/src/lib/dynamic-form.component.html +0 -137
- package/projects/dynamic-form-lib/src/lib/dynamic-form.component.scss +0 -141
- package/projects/dynamic-form-lib/src/lib/dynamic-form.component.ts +0 -366
- package/projects/dynamic-form-lib/src/lib/helpers/component-helper.ts +0 -54
- package/projects/dynamic-form-lib/src/lib/index.ts +0 -10
- package/projects/dynamic-form-lib/src/lib/models/dynamic-form-interfaces.ts +0 -117
- package/projects/dynamic-form-lib/src/lib/services/dynamic-form.service.spec.ts +0 -302
- package/projects/dynamic-form-lib/src/lib/services/dynamic-form.service.ts +0 -325
- package/projects/dynamic-form-lib/src/lib/style.scss +0 -3
- package/projects/dynamic-form-lib/src/lib/tailwind-output.css +0 -0
- package/projects/dynamic-form-lib/src/lib/validators/compare-validator.ts +0 -26
- package/projects/dynamic-form-lib/src/public-api.css +0 -1
- package/projects/dynamic-form-lib/src/public-api.ts +0 -10
- package/projects/dynamic-form-lib/tailwind.config.js +0 -10
- package/projects/dynamic-form-lib/tsconfig.lib.json +0 -15
- package/projects/dynamic-form-lib/tsconfig.lib.prod.json +0 -11
- package/projects/dynamic-form-lib/tsconfig.spec.json +0 -15
- package/public/favicon.ico +0 -0
- package/src/app/app-routing.module.ts +0 -10
- package/src/app/app.component.css +0 -0
- package/src/app/app.component.html +0 -18
- package/src/app/app.component.spec.ts +0 -35
- package/src/app/app.component.ts +0 -1038
- package/src/app/app.config.ts +0 -45
- package/src/app/app.module.ts +0 -46
- package/src/app/app.routes.ts +0 -8
- package/src/index.html +0 -13
- package/src/main.ts +0 -16
- package/src/styles.css +0 -2
- package/tailwind.config.js +0 -10
- package/tsconfig.app.json +0 -15
- package/tsconfig.json +0 -32
- package/tsconfig.spec.json +0 -15
- /package/{projects/dynamic-form-lib/src → src}/lib/style.css +0 -0
|
@@ -1,424 +0,0 @@
|
|
|
1
|
-
# Dynamic Form Component
|
|
2
|
-
|
|
3
|
-
A comprehensive, reusable dynamic form system for Angular applications with built-in validation and visual state management.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- 🎨 **Multiple Field Types**: text, email, number, select, checkbox, radio, date, textarea
|
|
8
|
-
- ✅ **Built-in Validation**: required, minLength, maxLength, min, max, email, pattern, custom validators
|
|
9
|
-
- 🎯 **Visual State Changes**: Real-time visual feedback for valid/invalid fields
|
|
10
|
-
- 📱 **Responsive Design**: Mobile-friendly layout using Bootstrap grid
|
|
11
|
-
- 🔄 **State Management**: Complete form state tracking (values, errors, touched fields)
|
|
12
|
-
- 🎭 **Conditional Display**: Show/hide fields based on form values
|
|
13
|
-
- 🎨 **PrimeNG Integration**: Uses PrimeNG components for consistent UI
|
|
14
|
-
- 🚀 **Standalone Components**: Uses Angular standalone components
|
|
15
|
-
|
|
16
|
-
## Installation
|
|
17
|
-
|
|
18
|
-
The dynamic form components are located in `src/app/dynamic-form/`.
|
|
19
|
-
|
|
20
|
-
### Required Dependencies
|
|
21
|
-
|
|
22
|
-
Make sure you have the following packages installed:
|
|
23
|
-
- `@angular/forms`
|
|
24
|
-
- `@angular/common`
|
|
25
|
-
- `primeng`
|
|
26
|
-
- `primeicons`
|
|
27
|
-
- `@primeng/themes`
|
|
28
|
-
|
|
29
|
-
## Usage
|
|
30
|
-
|
|
31
|
-
### Basic Example
|
|
32
|
-
|
|
33
|
-
```typescript
|
|
34
|
-
import { Component } from '@angular/core';
|
|
35
|
-
import { DynamicFormComponent } from './dynamic-form/dynamic-form.component';
|
|
36
|
-
import { DynamicFormConfig, DynamicFormValue } from './models/dynamic-forms';
|
|
37
|
-
|
|
38
|
-
@Component({
|
|
39
|
-
selector: 'app-example',
|
|
40
|
-
standalone: true,
|
|
41
|
-
imports: [DynamicFormComponent],
|
|
42
|
-
template: `
|
|
43
|
-
<app-dynamic-form
|
|
44
|
-
[config]="formConfig"
|
|
45
|
-
(formSubmit)="onSubmit($event)"
|
|
46
|
-
(formCancel)="onCancel()">
|
|
47
|
-
</app-dynamic-form>
|
|
48
|
-
`
|
|
49
|
-
})
|
|
50
|
-
export class ExampleComponent {
|
|
51
|
-
formConfig: DynamicFormConfig = {
|
|
52
|
-
id: 'example-form',
|
|
53
|
-
title: 'Example Form',
|
|
54
|
-
description: 'This is an example form',
|
|
55
|
-
fields: [
|
|
56
|
-
{
|
|
57
|
-
id: 'name',
|
|
58
|
-
label: 'Name',
|
|
59
|
-
type: 'text',
|
|
60
|
-
placeholder: 'Enter your name',
|
|
61
|
-
required: true,
|
|
62
|
-
validations: [
|
|
63
|
-
{
|
|
64
|
-
type: 'required',
|
|
65
|
-
message: 'Name is required'
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
id: 'email',
|
|
71
|
-
label: 'Email',
|
|
72
|
-
type: 'email',
|
|
73
|
-
placeholder: 'Enter your email',
|
|
74
|
-
required: true,
|
|
75
|
-
validations: [
|
|
76
|
-
{
|
|
77
|
-
type: 'required',
|
|
78
|
-
message: 'Email is required'
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
type: 'email',
|
|
82
|
-
message: 'Please enter a valid email'
|
|
83
|
-
}
|
|
84
|
-
]
|
|
85
|
-
}
|
|
86
|
-
],
|
|
87
|
-
submitLabel: 'Submit',
|
|
88
|
-
cancelLabel: 'Cancel'
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
onSubmit(values: DynamicFormValue): void {
|
|
92
|
-
console.log('Form submitted:', values);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
onCancel(): void {
|
|
96
|
-
console.log('Form cancelled');
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### Field Types
|
|
102
|
-
|
|
103
|
-
#### Text Input
|
|
104
|
-
```typescript
|
|
105
|
-
{
|
|
106
|
-
id: 'firstName',
|
|
107
|
-
label: 'First Name',
|
|
108
|
-
type: 'text',
|
|
109
|
-
placeholder: 'Enter first name',
|
|
110
|
-
required: true
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
#### Email Input
|
|
115
|
-
```typescript
|
|
116
|
-
{
|
|
117
|
-
id: 'email',
|
|
118
|
-
label: 'Email',
|
|
119
|
-
type: 'email',
|
|
120
|
-
placeholder: 'email@example.com',
|
|
121
|
-
required: true,
|
|
122
|
-
validations: [
|
|
123
|
-
{ type: 'required', message: 'Email is required' },
|
|
124
|
-
{ type: 'email', message: 'Invalid email format' }
|
|
125
|
-
]
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
#### Number Input
|
|
130
|
-
```typescript
|
|
131
|
-
{
|
|
132
|
-
id: 'age',
|
|
133
|
-
label: 'Age',
|
|
134
|
-
type: 'number',
|
|
135
|
-
validations: [
|
|
136
|
-
{ type: 'min', value: 18, message: 'Must be at least 18' },
|
|
137
|
-
{ type: 'max', value: 120, message: 'Must be less than 120' }
|
|
138
|
-
]
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
#### Select Dropdown
|
|
143
|
-
```typescript
|
|
144
|
-
{
|
|
145
|
-
id: 'country',
|
|
146
|
-
label: 'Country',
|
|
147
|
-
type: 'select',
|
|
148
|
-
required: true,
|
|
149
|
-
options: [
|
|
150
|
-
{ label: 'United States', value: 'US' },
|
|
151
|
-
{ label: 'Canada', value: 'CA' },
|
|
152
|
-
{ label: 'United Kingdom', value: 'UK' }
|
|
153
|
-
]
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
#### Radio Buttons
|
|
158
|
-
```typescript
|
|
159
|
-
{
|
|
160
|
-
id: 'gender',
|
|
161
|
-
label: 'Gender',
|
|
162
|
-
type: 'radio',
|
|
163
|
-
options: [
|
|
164
|
-
{ label: 'Male', value: 'male' },
|
|
165
|
-
{ label: 'Female', value: 'female' },
|
|
166
|
-
{ label: 'Other', value: 'other' }
|
|
167
|
-
]
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
#### Checkbox
|
|
172
|
-
```typescript
|
|
173
|
-
{
|
|
174
|
-
id: 'newsletter',
|
|
175
|
-
label: 'Subscribe to newsletter',
|
|
176
|
-
type: 'checkbox',
|
|
177
|
-
value: false
|
|
178
|
-
}
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
#### Date Picker
|
|
182
|
-
```typescript
|
|
183
|
-
{
|
|
184
|
-
id: 'birthDate',
|
|
185
|
-
label: 'Birth Date',
|
|
186
|
-
type: 'date',
|
|
187
|
-
placeholder: 'Select date',
|
|
188
|
-
required: true
|
|
189
|
-
}
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
#### Textarea
|
|
193
|
-
```typescript
|
|
194
|
-
{
|
|
195
|
-
id: 'comments',
|
|
196
|
-
label: 'Comments',
|
|
197
|
-
type: 'textarea',
|
|
198
|
-
placeholder: 'Enter comments',
|
|
199
|
-
validations: [
|
|
200
|
-
{ type: 'maxLength', value: 500, message: 'Max 500 characters' }
|
|
201
|
-
]
|
|
202
|
-
}
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### Validation Types
|
|
206
|
-
|
|
207
|
-
#### Required
|
|
208
|
-
```typescript
|
|
209
|
-
{
|
|
210
|
-
type: 'required',
|
|
211
|
-
message: 'This field is required'
|
|
212
|
-
}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
#### Min/Max Length
|
|
216
|
-
```typescript
|
|
217
|
-
{
|
|
218
|
-
type: 'minLength',
|
|
219
|
-
value: 3,
|
|
220
|
-
message: 'Minimum 3 characters'
|
|
221
|
-
},
|
|
222
|
-
{
|
|
223
|
-
type: 'maxLength',
|
|
224
|
-
value: 50,
|
|
225
|
-
message: 'Maximum 50 characters'
|
|
226
|
-
}
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
#### Min/Max Value
|
|
230
|
-
```typescript
|
|
231
|
-
{
|
|
232
|
-
type: 'min',
|
|
233
|
-
value: 0,
|
|
234
|
-
message: 'Value must be at least 0'
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
type: 'max',
|
|
238
|
-
value: 100,
|
|
239
|
-
message: 'Value must be at most 100'
|
|
240
|
-
}
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
#### Pattern (Regex)
|
|
244
|
-
```typescript
|
|
245
|
-
{
|
|
246
|
-
type: 'pattern',
|
|
247
|
-
value: '^[0-9]{5}$',
|
|
248
|
-
message: 'Must be a 5-digit ZIP code'
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
#### Custom Validator
|
|
253
|
-
```typescript
|
|
254
|
-
{
|
|
255
|
-
type: 'custom',
|
|
256
|
-
message: 'Password must contain at least one uppercase letter',
|
|
257
|
-
validator: (value: any) => {
|
|
258
|
-
return /[A-Z]/.test(value);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### Conditional Display
|
|
264
|
-
|
|
265
|
-
You can show/hide fields based on other field values:
|
|
266
|
-
|
|
267
|
-
```typescript
|
|
268
|
-
{
|
|
269
|
-
id: 'companyName',
|
|
270
|
-
label: 'Company Name',
|
|
271
|
-
type: 'text',
|
|
272
|
-
conditionalDisplay: (formValues: any) => {
|
|
273
|
-
return formValues.accountType === 'business';
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
### Field Ordering and Layout
|
|
279
|
-
|
|
280
|
-
Control field order and layout using `order` and `cssClass`:
|
|
281
|
-
|
|
282
|
-
```typescript
|
|
283
|
-
{
|
|
284
|
-
id: 'firstName',
|
|
285
|
-
label: 'First Name',
|
|
286
|
-
type: 'text',
|
|
287
|
-
order: 1,
|
|
288
|
-
cssClass: 'col-md-6' // Bootstrap grid class
|
|
289
|
-
}
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
### Form State Management
|
|
293
|
-
|
|
294
|
-
Track form state in real-time:
|
|
295
|
-
|
|
296
|
-
```typescript
|
|
297
|
-
onFormStateChange(state: DynamicFormState): void {
|
|
298
|
-
console.log('Form valid:', state.isValid);
|
|
299
|
-
console.log('Current values:', state.values);
|
|
300
|
-
console.log('Errors:', state.errors);
|
|
301
|
-
console.log('Touched fields:', state.touched);
|
|
302
|
-
console.log('Submitting:', state.isSubmitting);
|
|
303
|
-
}
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
### Initial Values
|
|
307
|
-
|
|
308
|
-
Provide initial values to the form:
|
|
309
|
-
|
|
310
|
-
```typescript
|
|
311
|
-
<app-dynamic-form
|
|
312
|
-
[config]="formConfig"
|
|
313
|
-
[initialValues]="{ firstName: 'John', email: 'john@example.com' }"
|
|
314
|
-
(formSubmit)="onSubmit($event)">
|
|
315
|
-
</app-dynamic-form>
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
## Component API
|
|
319
|
-
|
|
320
|
-
### Inputs
|
|
321
|
-
|
|
322
|
-
| Input | Type | Description |
|
|
323
|
-
|-------|------|-------------|
|
|
324
|
-
| `config` | `DynamicFormConfig` | Form configuration (required) |
|
|
325
|
-
| `initialValues` | `DynamicFormValue` | Initial form values (optional) |
|
|
326
|
-
|
|
327
|
-
### Outputs
|
|
328
|
-
|
|
329
|
-
| Output | Type | Description |
|
|
330
|
-
|--------|------|-------------|
|
|
331
|
-
| `formSubmit` | `DynamicFormValue` | Emitted when form is submitted |
|
|
332
|
-
| `formCancel` | `void` | Emitted when cancel is clicked |
|
|
333
|
-
| `formStateChange` | `DynamicFormState` | Emitted when form state changes |
|
|
334
|
-
|
|
335
|
-
### Methods
|
|
336
|
-
|
|
337
|
-
The component exposes these methods via ViewChild:
|
|
338
|
-
|
|
339
|
-
- `reset()`: Reset the form to initial state
|
|
340
|
-
- `patchValues(values: DynamicFormValue)`: Update form values
|
|
341
|
-
- `getFormValue()`: Get current form values
|
|
342
|
-
|
|
343
|
-
## Demo Component
|
|
344
|
-
|
|
345
|
-
A complete demo component is available at `src/app/dynamic-form/dynamic-form-demo/` that showcases all features.
|
|
346
|
-
|
|
347
|
-
To use the demo:
|
|
348
|
-
1. Import and add to your routes
|
|
349
|
-
2. Navigate to the demo route
|
|
350
|
-
3. Interact with the form to see validation and state changes
|
|
351
|
-
|
|
352
|
-
## Styling
|
|
353
|
-
|
|
354
|
-
The components use a combination of:
|
|
355
|
-
- Bootstrap grid system for layout
|
|
356
|
-
- PrimeNG component styles
|
|
357
|
-
- Custom SCSS for visual state changes
|
|
358
|
-
|
|
359
|
-
Visual states include:
|
|
360
|
-
- ✅ Valid fields (green border + checkmark)
|
|
361
|
-
- ❌ Invalid fields (red border + error messages)
|
|
362
|
-
- 🔒 Disabled fields (grayed out)
|
|
363
|
-
- ⭐ Required fields (asterisk indicator)
|
|
364
|
-
|
|
365
|
-
## Service
|
|
366
|
-
|
|
367
|
-
The `DynamicFormService` provides:
|
|
368
|
-
- Validator creation from validation config
|
|
369
|
-
- Error message generation
|
|
370
|
-
- Form configuration validation
|
|
371
|
-
- Sample form configuration generator
|
|
372
|
-
|
|
373
|
-
## File Structure
|
|
374
|
-
|
|
375
|
-
```
|
|
376
|
-
src/app/dynamic-form/
|
|
377
|
-
├── dynamic-form.component.ts
|
|
378
|
-
├── dynamic-form.component.html
|
|
379
|
-
├── dynamic-form.component.scss
|
|
380
|
-
├── dynamic-form-field/
|
|
381
|
-
│ ├── dynamic-form-field.component.ts
|
|
382
|
-
│ ├── dynamic-form-field.component.html
|
|
383
|
-
│ └── dynamic-form-field.component.scss
|
|
384
|
-
├── services/
|
|
385
|
-
│ └── dynamic-form.service.ts
|
|
386
|
-
├── dynamic-form-demo/
|
|
387
|
-
│ ├── dynamic-form-demo.component.ts
|
|
388
|
-
│ ├── dynamic-form-demo.component.html
|
|
389
|
-
│ └── dynamic-form-demo.component.scss
|
|
390
|
-
└── README.md
|
|
391
|
-
```
|
|
392
|
-
|
|
393
|
-
## TypeScript Interfaces
|
|
394
|
-
|
|
395
|
-
All interfaces are defined in `src/app/models/dynamic-forms.ts`:
|
|
396
|
-
|
|
397
|
-
- `DynamicFormField`: Field configuration
|
|
398
|
-
- `DynamicFormOption`: Select/Radio options
|
|
399
|
-
- `DynamicFormValidation`: Validation rules
|
|
400
|
-
- `DynamicFormConfig`: Complete form configuration
|
|
401
|
-
- `DynamicFormValue`: Form values object
|
|
402
|
-
- `DynamicFormError`: Error representation
|
|
403
|
-
- `DynamicFormState`: Complete form state
|
|
404
|
-
|
|
405
|
-
## Best Practices
|
|
406
|
-
|
|
407
|
-
1. **Always provide validation messages**: Users need clear feedback
|
|
408
|
-
2. **Use appropriate field types**: Choose the right input type for data
|
|
409
|
-
3. **Order fields logically**: Use the `order` property
|
|
410
|
-
4. **Group related fields**: Use `cssClass` for layout
|
|
411
|
-
5. **Handle form submission**: Always provide feedback after submission
|
|
412
|
-
6. **Validate configuration**: Use `DynamicFormService.validateFormConfig()`
|
|
413
|
-
|
|
414
|
-
## Browser Support
|
|
415
|
-
|
|
416
|
-
Supports all modern browsers that Angular 19 supports:
|
|
417
|
-
- Chrome (latest)
|
|
418
|
-
- Firefox (latest)
|
|
419
|
-
- Safari (latest)
|
|
420
|
-
- Edge (latest)
|
|
421
|
-
|
|
422
|
-
## License
|
|
423
|
-
|
|
424
|
-
Part of the VesselRegistry application.
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
# Dynamic Form System - Summary
|
|
2
|
-
|
|
3
|
-
## Created Files
|
|
4
|
-
|
|
5
|
-
The following files have been successfully created in `vesselregistry.client/src/app/dynamic-form/`:
|
|
6
|
-
|
|
7
|
-
### Core Components
|
|
8
|
-
1. **dynamic-form.component.ts** - Main container component that manages the entire form
|
|
9
|
-
2. **dynamic-form.component.html** - Template for the form container
|
|
10
|
-
3. **dynamic-form.component.scss** - Styles for the form container
|
|
11
|
-
|
|
12
|
-
### Field Component
|
|
13
|
-
4. **dynamic-form-field/dynamic-form-field.component.ts** - Individual field renderer
|
|
14
|
-
5. **dynamic-form-field/dynamic-form-field.component.html** - Template for individual fields
|
|
15
|
-
6. **dynamic-form-field/dynamic-form-field.component.scss** - Styles for fields with visual states
|
|
16
|
-
|
|
17
|
-
### Service
|
|
18
|
-
7. **services/dynamic-form.service.ts** - Form validation and state management service
|
|
19
|
-
8. **services/dynamic-form.service.spec.ts** - Unit tests for the service
|
|
20
|
-
|
|
21
|
-
### Demo Component
|
|
22
|
-
9. **dynamic-form-demo/dynamic-form-demo.component.ts** - Demonstration component
|
|
23
|
-
10. **dynamic-form-demo/dynamic-form-demo.component.html** - Demo template
|
|
24
|
-
11. **dynamic-form-demo/dynamic-form-demo.component.scss** - Demo styles
|
|
25
|
-
|
|
26
|
-
### Documentation
|
|
27
|
-
12. **README.md** - Comprehensive documentation with examples
|
|
28
|
-
13. **index.ts** - Barrel export file for easy imports
|
|
29
|
-
|
|
30
|
-
## Features Implemented
|
|
31
|
-
|
|
32
|
-
### ✅ Field Types
|
|
33
|
-
- Text input
|
|
34
|
-
- Email input
|
|
35
|
-
- Number input
|
|
36
|
-
- Select dropdown (with PrimeNG Dropdown)
|
|
37
|
-
- Radio buttons (with PrimeNG RadioButton)
|
|
38
|
-
- Checkbox (with PrimeNG Checkbox)
|
|
39
|
-
- Date picker (with PrimeNG Calendar)
|
|
40
|
-
- Textarea
|
|
41
|
-
|
|
42
|
-
### ✅ Validation
|
|
43
|
-
- Required
|
|
44
|
-
- Min/Max length
|
|
45
|
-
- Min/Max value
|
|
46
|
-
- Email format
|
|
47
|
-
- Pattern (regex)
|
|
48
|
-
- Custom validators
|
|
49
|
-
|
|
50
|
-
### ✅ Visual State Changes
|
|
51
|
-
- **Valid fields**: Green border + checkmark icon (animated fadeIn)
|
|
52
|
-
- **Invalid fields**: Red border + error messages (animated slideDown)
|
|
53
|
-
- **Disabled fields**: Grayed out appearance
|
|
54
|
-
- **Required fields**: Asterisk indicator
|
|
55
|
-
- **Touched/Dirty states**: Visual feedback based on interaction
|
|
56
|
-
|
|
57
|
-
### ✅ Advanced Features
|
|
58
|
-
- Conditional field display based on form values
|
|
59
|
-
- Field ordering system
|
|
60
|
-
- Bootstrap grid integration for responsive layout
|
|
61
|
-
- Custom CSS classes per field
|
|
62
|
-
- Initial values support
|
|
63
|
-
- Form state tracking (values, errors, touched, isSubmitting, isValid)
|
|
64
|
-
- Real-time validation
|
|
65
|
-
- Form reset functionality
|
|
66
|
-
- Value patching
|
|
67
|
-
|
|
68
|
-
### ✅ Styling
|
|
69
|
-
- Smooth transitions and animations
|
|
70
|
-
- Responsive design (mobile-friendly)
|
|
71
|
-
- PrimeNG component integration
|
|
72
|
-
- Bootstrap grid system
|
|
73
|
-
- Custom visual states with color coding
|
|
74
|
-
- Accessible form labels and error messages
|
|
75
|
-
|
|
76
|
-
## Architecture
|
|
77
|
-
|
|
78
|
-
### Component Hierarchy
|
|
79
|
-
```
|
|
80
|
-
DynamicFormComponent (Container)
|
|
81
|
-
└── DynamicFormFieldComponent (Field Renderer)
|
|
82
|
-
└── PrimeNG Components (UI Elements)
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Data Flow
|
|
86
|
-
1. Parent provides `DynamicFormConfig`
|
|
87
|
-
2. `DynamicFormComponent` builds Angular `FormGroup`
|
|
88
|
-
3. `DynamicFormService` creates validators
|
|
89
|
-
4. `DynamicFormFieldComponent` renders appropriate field type
|
|
90
|
-
5. Form state tracked and emitted via `formStateChange`
|
|
91
|
-
6. Submission handled via `formSubmit` event
|
|
92
|
-
|
|
93
|
-
## Integration Points
|
|
94
|
-
|
|
95
|
-
### With Existing Project
|
|
96
|
-
- Uses existing PrimeNG components (already installed)
|
|
97
|
-
- Follows Bootstrap grid conventions (already in use)
|
|
98
|
-
- Standalone components (Angular 19 best practice)
|
|
99
|
-
- Compatible with existing form patterns
|
|
100
|
-
|
|
101
|
-
### TypeScript Interfaces
|
|
102
|
-
All interfaces defined in `vesselregistry.client/src/app/models/dynamic-forms.ts`:
|
|
103
|
-
- `DynamicFormField`
|
|
104
|
-
- `DynamicFormOption`
|
|
105
|
-
- `DynamicFormValidation`
|
|
106
|
-
- `DynamicFormConfig`
|
|
107
|
-
- `DynamicFormValue`
|
|
108
|
-
- `DynamicFormError`
|
|
109
|
-
- `DynamicFormState`
|
|
110
|
-
|
|
111
|
-
## Usage Example
|
|
112
|
-
|
|
113
|
-
```typescript
|
|
114
|
-
import { DynamicFormComponent } from './dynamic-form/dynamic-form.component';
|
|
115
|
-
import { DynamicFormConfig } from './models/dynamic-forms';
|
|
116
|
-
|
|
117
|
-
formConfig: DynamicFormConfig = {
|
|
118
|
-
id: 'my-form',
|
|
119
|
-
title: 'Contact Form',
|
|
120
|
-
fields: [
|
|
121
|
-
{
|
|
122
|
-
id: 'name',
|
|
123
|
-
label: 'Name',
|
|
124
|
-
type: 'text',
|
|
125
|
-
required: true,
|
|
126
|
-
validations: [
|
|
127
|
-
{ type: 'required', message: 'Name is required' }
|
|
128
|
-
]
|
|
129
|
-
}
|
|
130
|
-
]
|
|
131
|
-
};
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## Testing
|
|
135
|
-
|
|
136
|
-
- Unit tests provided for `DynamicFormService`
|
|
137
|
-
- Test coverage for validators and error messages
|
|
138
|
-
- Demo component available for manual testing
|
|
139
|
-
|
|
140
|
-
## Next Steps
|
|
141
|
-
|
|
142
|
-
To use the dynamic form system:
|
|
143
|
-
|
|
144
|
-
1. Import `DynamicFormComponent` in your component
|
|
145
|
-
2. Create a `DynamicFormConfig` object
|
|
146
|
-
3. Handle `formSubmit` and `formCancel` events
|
|
147
|
-
4. Optionally track state with `formStateChange`
|
|
148
|
-
|
|
149
|
-
See `README.md` for detailed examples and API documentation.
|
|
150
|
-
|
|
151
|
-
## Status
|
|
152
|
-
|
|
153
|
-
✅ All files created successfully
|
|
154
|
-
✅ No TypeScript compilation errors
|
|
155
|
-
✅ Follows Angular 19 and PrimeNG conventions
|
|
156
|
-
✅ Includes comprehensive documentation
|
|
157
|
-
✅ Visual states implemented with animations
|
|
158
|
-
✅ Fully responsive design
|
|
159
|
-
✅ Unit tests included
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { Directive, ElementRef, Input } from '@angular/core';
|
|
2
|
-
import { RadioButton } from 'primeng/radiobutton';
|
|
3
|
-
|
|
4
|
-
@Directive({
|
|
5
|
-
selector: '[dynamicRef]',
|
|
6
|
-
standalone: true
|
|
7
|
-
})
|
|
8
|
-
export class DynamicRefDirective {
|
|
9
|
-
@Input() refKey!: string;
|
|
10
|
-
constructor(public el: ElementRef) {
|
|
11
|
-
const t = this.refKey;
|
|
12
|
-
}
|
|
13
|
-
}
|
package/projects/dynamic-form-lib/src/lib/dynamic-form-demo/dynamic-form-demo.component.html
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
<div class="demo-container">
|
|
2
|
-
<div class="container-fluid">
|
|
3
|
-
<div class="row">
|
|
4
|
-
<div class="col-md-8">
|
|
5
|
-
<app-dynamic-form
|
|
6
|
-
[config]="formConfig"
|
|
7
|
-
[initialValues]="formValues"
|
|
8
|
-
(formSubmit)="onFormSubmit($event)"
|
|
9
|
-
(formCancel)="onFormCancel()"
|
|
10
|
-
(formStateChange)="onFormStateChange($event)"
|
|
11
|
-
></app-dynamic-form>
|
|
12
|
-
</div>
|
|
13
|
-
|
|
14
|
-
<div class="col-md-4">
|
|
15
|
-
<div class="info-panel card-style card-corner-style">
|
|
16
|
-
<h5>Form Status</h5>
|
|
17
|
-
<hr />
|
|
18
|
-
|
|
19
|
-
<div class="status-item">
|
|
20
|
-
<label>Form Valid:</label>
|
|
21
|
-
<span [class]="formIsValid ? 'status-success' : 'status-error'">
|
|
22
|
-
{{ formIsValid ? 'Yes' : 'No' }}
|
|
23
|
-
</span>
|
|
24
|
-
</div>
|
|
25
|
-
|
|
26
|
-
<div class="status-item">
|
|
27
|
-
<label>Error Count:</label>
|
|
28
|
-
<span [class]="formErrorCount > 0 ? 'status-error' : 'status-success'">
|
|
29
|
-
{{ formErrorCount }}
|
|
30
|
-
</span>
|
|
31
|
-
</div>
|
|
32
|
-
|
|
33
|
-
@if (formState?.isSubmitting) {
|
|
34
|
-
<div class="status-item">
|
|
35
|
-
<label>Status:</label>
|
|
36
|
-
<span class="status-info">Submitting...</span>
|
|
37
|
-
</div>
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
@if (formState?.errors && formState.errors.length > 0) {
|
|
41
|
-
<div class="errors-section">
|
|
42
|
-
<h6>Current Errors:</h6>
|
|
43
|
-
<ul>
|
|
44
|
-
@for (error of formState.errors; track error) {
|
|
45
|
-
<li class="error-item">
|
|
46
|
-
<strong>{{ error.fieldId }}:</strong> {{ error.message }}
|
|
47
|
-
</li>
|
|
48
|
-
}
|
|
49
|
-
</ul>
|
|
50
|
-
</div>
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
@if (submittedData) {
|
|
54
|
-
<div class="submitted-data">
|
|
55
|
-
<h6>Submitted Data:</h6>
|
|
56
|
-
<pre>{{ submittedData | json }}</pre>
|
|
57
|
-
</div>
|
|
58
|
-
}
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
<div class="help-panel card-style card-corner-style">
|
|
62
|
-
<h5>Instructions</h5>
|
|
63
|
-
<hr />
|
|
64
|
-
<ul>
|
|
65
|
-
<li>Fill out all required fields (marked with *)</li>
|
|
66
|
-
<li>Fields will show validation errors when touched</li>
|
|
67
|
-
<li>Valid fields will show a green checkmark</li>
|
|
68
|
-
<li>Form state is tracked in real-time</li>
|
|
69
|
-
<li>Click Submit to see the form data</li>
|
|
70
|
-
</ul>
|
|
71
|
-
</div>
|
|
72
|
-
</div>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|