@vipsolucoes/dynamic-form 1.0.1
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
ADDED
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
# @vipsolucoes/dynamic-form
|
|
2
|
+
|
|
3
|
+
Biblioteca Angular para criação de formulários dinâmicos baseados em configuração, construída com PrimeNG e Reactive Forms.
|
|
4
|
+
|
|
5
|
+
## 📦 Instalação
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @vipsolucoes/dynamic-form
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### Dependências
|
|
12
|
+
|
|
13
|
+
Esta biblioteca requer as seguintes dependências peer:
|
|
14
|
+
|
|
15
|
+
- `@angular/core`: ^19.0.0 || ^20.0.0 || ^21.0.0
|
|
16
|
+
- `@angular/common`: ^19.0.0 || ^20.0.0 || ^21.0.0
|
|
17
|
+
- `@angular/forms`: ^19.0.0 || ^20.0.0 || ^21.0.0
|
|
18
|
+
- `primeng`: ^19.0.0 || ^20.0.0 || ^21.0.0
|
|
19
|
+
|
|
20
|
+
## 🚀 Uso Básico
|
|
21
|
+
|
|
22
|
+
### 1. Importe o módulo no seu componente
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { Component } from '@angular/core';
|
|
26
|
+
import { FormGroup } from '@angular/forms';
|
|
27
|
+
import { DynamicFormComponent, iFormConfig } from '@vipsolucoes/dynamic-form';
|
|
28
|
+
import { Validators } from '@angular/forms';
|
|
29
|
+
|
|
30
|
+
@Component({
|
|
31
|
+
selector: 'app-example',
|
|
32
|
+
standalone: true,
|
|
33
|
+
imports: [DynamicFormComponent],
|
|
34
|
+
template: `
|
|
35
|
+
<vp-dynamic-form [config]="formConfig" (formReady)="onFormReady($event)"> </vp-dynamic-form>
|
|
36
|
+
`,
|
|
37
|
+
})
|
|
38
|
+
export class ExampleComponent {
|
|
39
|
+
formConfig: iFormConfig[] = [
|
|
40
|
+
{
|
|
41
|
+
key: 'nome',
|
|
42
|
+
controlType: 'text',
|
|
43
|
+
label: 'Nome',
|
|
44
|
+
placeholder: 'Digite seu nome',
|
|
45
|
+
validators: [Validators.required, Validators.minLength(3)],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
key: 'email',
|
|
49
|
+
controlType: 'email',
|
|
50
|
+
label: 'E-mail',
|
|
51
|
+
placeholder: 'Digite seu e-mail',
|
|
52
|
+
validators: [Validators.required, Validators.email],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
key: 'idade',
|
|
56
|
+
controlType: 'number',
|
|
57
|
+
label: 'Idade',
|
|
58
|
+
validators: [Validators.required, Validators.min(18)],
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
onFormReady(form: FormGroup): void {
|
|
63
|
+
console.log('Formulário pronto:', form);
|
|
64
|
+
// Acesse o formulário e seus valores
|
|
65
|
+
form.valueChanges.subscribe((values) => {
|
|
66
|
+
console.log('Valores do formulário:', values);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 2. Controle de Submissão
|
|
73
|
+
|
|
74
|
+
O componente **não possui botão de submit interno**. O controle de submissão deve ser feito pelo componente pai usando `@ViewChild`:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { Component, ViewChild } from '@angular/core';
|
|
78
|
+
import { DynamicFormComponent } from '@vipsolucoes/dynamic-form';
|
|
79
|
+
import { FormGroup } from '@angular/forms';
|
|
80
|
+
|
|
81
|
+
@Component({
|
|
82
|
+
selector: 'app-example',
|
|
83
|
+
standalone: true,
|
|
84
|
+
imports: [DynamicFormComponent],
|
|
85
|
+
template: `
|
|
86
|
+
<vp-dynamic-form #myForm [config]="formConfig" />
|
|
87
|
+
<button (click)="onSubmit()">Enviar</button>
|
|
88
|
+
`,
|
|
89
|
+
})
|
|
90
|
+
export class ExampleComponent {
|
|
91
|
+
@ViewChild('myForm') myForm!: DynamicFormComponent;
|
|
92
|
+
|
|
93
|
+
formConfig: iFormConfig[] = [
|
|
94
|
+
// ... sua configuração
|
|
95
|
+
];
|
|
96
|
+
|
|
97
|
+
onSubmit(): void {
|
|
98
|
+
if (this.myForm.form.valid) {
|
|
99
|
+
console.log('Dados:', this.myForm.form.value);
|
|
100
|
+
// Enviar dados ao backend
|
|
101
|
+
} else {
|
|
102
|
+
this.myForm.form.markAllAsTouched();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 📝 Tipos de Campos Suportados
|
|
109
|
+
|
|
110
|
+
A biblioteca suporta os seguintes tipos de campos:
|
|
111
|
+
|
|
112
|
+
- `text` - Campo de texto
|
|
113
|
+
- `email` - Campo de e-mail
|
|
114
|
+
- `password` - Campo de senha
|
|
115
|
+
- `number` - Campo numérico
|
|
116
|
+
- `select` - Dropdown/Select
|
|
117
|
+
- `datepicker` - Seletor de data
|
|
118
|
+
- `textarea` - Área de texto
|
|
119
|
+
- `toggleswitch` - Switch/Toggle
|
|
120
|
+
|
|
121
|
+
## 🎯 Exemplos de Configuração
|
|
122
|
+
|
|
123
|
+
### Campo de Texto
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
{
|
|
127
|
+
key: 'nome',
|
|
128
|
+
controlType: 'text',
|
|
129
|
+
label: 'Nome Completo',
|
|
130
|
+
placeholder: 'Digite seu nome',
|
|
131
|
+
value: '', // Valor inicial
|
|
132
|
+
hint: 'Este campo é obrigatório',
|
|
133
|
+
validators: [Validators.required]
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Campo Select
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
{
|
|
141
|
+
key: 'pais',
|
|
142
|
+
controlType: 'select',
|
|
143
|
+
label: 'País',
|
|
144
|
+
placeholder: 'Selecione um país',
|
|
145
|
+
options: [
|
|
146
|
+
{ label: 'Brasil', value: 'BR' },
|
|
147
|
+
{ label: 'Estados Unidos', value: 'US' },
|
|
148
|
+
{ label: 'Portugal', value: 'PT' }
|
|
149
|
+
],
|
|
150
|
+
validators: [Validators.required]
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Campo DatePicker
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
{
|
|
158
|
+
key: 'dataNascimento',
|
|
159
|
+
controlType: 'datepicker',
|
|
160
|
+
label: 'Data de Nascimento',
|
|
161
|
+
dateFormat: 'dd/mm/yyyy',
|
|
162
|
+
dateViewType: 'date', // 'date' | 'month' | 'year'
|
|
163
|
+
validators: [Validators.required]
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Campo Textarea
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
{
|
|
171
|
+
key: 'observacoes',
|
|
172
|
+
controlType: 'textarea',
|
|
173
|
+
label: 'Observações',
|
|
174
|
+
placeholder: 'Digite suas observações',
|
|
175
|
+
textareaAutoResize: true,
|
|
176
|
+
textareaRows: 5,
|
|
177
|
+
validators: [Validators.maxLength(500)]
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Campo ToggleSwitch
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
{
|
|
185
|
+
key: 'aceitaTermos',
|
|
186
|
+
controlType: 'toggleswitch',
|
|
187
|
+
label: 'Aceito os termos e condições',
|
|
188
|
+
value: false,
|
|
189
|
+
toggleTrueValue: true,
|
|
190
|
+
toggleFalseValue: false
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Campos Condicionais
|
|
195
|
+
|
|
196
|
+
Você pode fazer campos serem habilitados/desabilitados baseado no valor de um toggle switch:
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
{
|
|
200
|
+
key: 'notificacoes',
|
|
201
|
+
controlType: 'toggleswitch',
|
|
202
|
+
label: 'Receber notificações'
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
key: 'emailNotificacao',
|
|
206
|
+
controlType: 'email',
|
|
207
|
+
label: 'E-mail para notificações',
|
|
208
|
+
placeholder: 'Digite seu e-mail',
|
|
209
|
+
enabledWhen: 'notificacoes', // Campo será habilitado quando 'notificacoes' for true
|
|
210
|
+
validators: [Validators.required, Validators.email]
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Layout Customizado com styleClass
|
|
215
|
+
|
|
216
|
+
Use a propriedade `styleClass` para criar layouts customizados em grid:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
const layoutConfig: iFormConfig[] = [
|
|
220
|
+
{
|
|
221
|
+
key: 'firstName',
|
|
222
|
+
controlType: 'text',
|
|
223
|
+
label: 'Primeiro Nome',
|
|
224
|
+
validators: [Validators.required],
|
|
225
|
+
styleClass: 'grid-col-6', // Ocupa 6 colunas (50%)
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
key: 'lastName',
|
|
229
|
+
controlType: 'text',
|
|
230
|
+
label: 'Sobrenome',
|
|
231
|
+
validators: [Validators.required],
|
|
232
|
+
styleClass: 'grid-col-6', // Ocupa 6 colunas (50%)
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
key: 'email',
|
|
236
|
+
controlType: 'email',
|
|
237
|
+
label: 'E-mail',
|
|
238
|
+
validators: [Validators.required, Validators.email],
|
|
239
|
+
styleClass: 'grid-col-12', // Ocupa 12 colunas (100%)
|
|
240
|
+
},
|
|
241
|
+
];
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
Você precisará definir as classes CSS no seu componente ou globalmente:
|
|
245
|
+
|
|
246
|
+
```css
|
|
247
|
+
.form-grid-layout {
|
|
248
|
+
display: grid;
|
|
249
|
+
grid-template-columns: repeat(12, 1fr);
|
|
250
|
+
gap: 1rem;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.grid-col-12 {
|
|
254
|
+
grid-column: span 12;
|
|
255
|
+
}
|
|
256
|
+
.grid-col-6 {
|
|
257
|
+
grid-column: span 6;
|
|
258
|
+
}
|
|
259
|
+
.grid-col-4 {
|
|
260
|
+
grid-column: span 4;
|
|
261
|
+
}
|
|
262
|
+
.grid-col-3 {
|
|
263
|
+
grid-column: span 3;
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## 🔧 API
|
|
268
|
+
|
|
269
|
+
### DynamicFormComponent
|
|
270
|
+
|
|
271
|
+
#### Inputs
|
|
272
|
+
|
|
273
|
+
- `config: iFormConfig[]` (obrigatório) - Array com a configuração dos campos do formulário
|
|
274
|
+
|
|
275
|
+
#### Outputs
|
|
276
|
+
|
|
277
|
+
- `formReady: FormGroup` - Emite o FormGroup quando o formulário está pronto
|
|
278
|
+
|
|
279
|
+
#### Métodos Públicos
|
|
280
|
+
|
|
281
|
+
- `getControl(key: string): AbstractControl` - Obtém um controle do formulário pela chave
|
|
282
|
+
|
|
283
|
+
### Interface iFormConfig
|
|
284
|
+
|
|
285
|
+
```typescript
|
|
286
|
+
interface iFormConfig {
|
|
287
|
+
key: string; // Identificador único do campo
|
|
288
|
+
controlType:
|
|
289
|
+
| 'text'
|
|
290
|
+
| 'password'
|
|
291
|
+
| 'email'
|
|
292
|
+
| 'number'
|
|
293
|
+
| 'select'
|
|
294
|
+
| 'datepicker'
|
|
295
|
+
| 'textarea'
|
|
296
|
+
| 'toggleswitch';
|
|
297
|
+
label: string; // Texto do label
|
|
298
|
+
value?: any; // Valor inicial
|
|
299
|
+
placeholder?: string; // Texto de placeholder
|
|
300
|
+
hint?: string; // Texto de ajuda
|
|
301
|
+
disabled?: boolean; // Campo desabilitado
|
|
302
|
+
enabledWhen?: string; // Chave do toggle que controla este campo
|
|
303
|
+
styleClass?: string; // Classes CSS customizadas
|
|
304
|
+
options?: iFieldOption[]; // Opções para select (obrigatório se controlType for 'select')
|
|
305
|
+
validators?: ValidatorFn[]; // Validadores Angular
|
|
306
|
+
dateFormat?: string; // Formato da data (default: 'dd/mm/yyyy')
|
|
307
|
+
dateViewType?: 'date' | 'month' | 'year'; // Tipo de visualização da data (default: 'date')
|
|
308
|
+
textareaAutoResize?: boolean; // Auto-resize do textarea (default: false)
|
|
309
|
+
textareaRows?: number; // Número de linhas do textarea
|
|
310
|
+
textareaCols?: number; // Número de colunas do textarea
|
|
311
|
+
toggleTrueValue?: any; // Valor quando toggle está ativo (default: true)
|
|
312
|
+
toggleFalseValue?: any; // Valor quando toggle está inativo (default: false)
|
|
313
|
+
}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## 🎨 Customização de Campos
|
|
317
|
+
|
|
318
|
+
Você pode registrar campos customizados usando o `FieldRegistryService`:
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
import { FieldRegistryService } from '@vipsolucoes/dynamic-form';
|
|
322
|
+
import { CustomFieldComponent } from './custom-field.component';
|
|
323
|
+
|
|
324
|
+
export class AppComponent {
|
|
325
|
+
constructor(private fieldRegistry: FieldRegistryService) {
|
|
326
|
+
// Registra um campo customizado
|
|
327
|
+
this.fieldRegistry.registerField('custom', CustomFieldComponent);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Depois, use o tipo customizado na configuração:
|
|
333
|
+
|
|
334
|
+
```typescript
|
|
335
|
+
{
|
|
336
|
+
key: 'campoCustom',
|
|
337
|
+
controlType: 'custom',
|
|
338
|
+
label: 'Campo Customizado'
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## 🌐 Customização de Mensagens de Erro
|
|
343
|
+
|
|
344
|
+
Você pode personalizar as mensagens de erro através do provider:
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
import { provideDynamicFormConfig } from '@vipsolucoes/dynamic-form';
|
|
348
|
+
import { ApplicationConfig } from '@angular/core';
|
|
349
|
+
|
|
350
|
+
export const appConfig: ApplicationConfig = {
|
|
351
|
+
providers: [
|
|
352
|
+
provideDynamicFormConfig({
|
|
353
|
+
required: 'Este campo é obrigatório',
|
|
354
|
+
email: 'E-mail inválido',
|
|
355
|
+
minlength: (requiredLength: number) => `Mínimo de ${requiredLength} caracteres necessários`,
|
|
356
|
+
maxlength: (requiredLength: number) => `Máximo de ${requiredLength} caracteres permitidos`,
|
|
357
|
+
custom: (error: any) => error.message || 'Erro de validação',
|
|
358
|
+
}),
|
|
359
|
+
],
|
|
360
|
+
};
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**Nota:** As mensagens `minlength` e `maxlength` são funções que recebem o comprimento requerido como parâmetro. A função `custom` permite tratar erros de validação personalizados.
|
|
364
|
+
|
|
365
|
+
## 🛠️ Desenvolvimento
|
|
366
|
+
|
|
367
|
+
### Build da biblioteca
|
|
368
|
+
|
|
369
|
+
```bash
|
|
370
|
+
ng build dynamic-form
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
### Publicação no npm
|
|
374
|
+
|
|
375
|
+
Após o build:
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
cd dist/dynamic-form
|
|
379
|
+
npm publish
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
## 📄 Licença
|
|
383
|
+
|
|
384
|
+
MIT
|
|
385
|
+
|
|
386
|
+
## 🔗 Links
|
|
387
|
+
|
|
388
|
+
- [Repositório](https://github.com/vipsolucoes/dynamic-form)
|
|
389
|
+
- [Issues](https://github.com/vipsolucoes/dynamic-form/issues)
|