# Formulário Dinâmico

O Cat Ui utiliza um conceito de builder onde com chamadas de métodos encadeados permitirá a criação de formulários sem a necessidade de HTML e CSS, focando apenas na regra de negócio, garantindo assim, mais produtividade.

### API

#### fieldset

Crie sessões de formulários, onde cada fieldset pussuirá seu builder para a criação dos campos internos a ele

#### onChange

Cada modificação de qualquer campo no formulário emitirá seu objeto, contendo todos os dados já  informados.

#### onSubmit

Ao realizar um submit no formulário, o mesmo será convertido em um objeto e retornado como parâmetro de uma função, permitindo o envio para meios externos.

#### generate

Gera as configurações necessárias para a criação do formulário

### Uso

{% tabs %}
{% tab title="form-example.module.ts" %}

```typescript
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';

import { CatFormModule } from '@catrx/ui/form';

import { FormExampleComponent } from './form-example.component';

@NgModule({
  declarations: [PageFormComponent],
  imports: [CatFormModule, HttpClientModule]
})
export class PageFormModule {}
```

{% endtab %}

{% tab title="form-example.service.ts" %}

```typescript
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { CatFormListOptions } from '@catrx/ui/form';
import { delay } from 'rxjs/internal/operators/delay';
import { first } from 'rxjs/internal/operators/first';
import { map } from 'rxjs/internal/operators/map';

@Injectable({
  providedIn: 'root',
})
export class FormExampleService {
  constructor(private http: HttpClient) {}

  public getAddressByZipCode(zipcode: string) {
    return this.http
      .get<any>(`https://viacep.com.br/ws/${zipcode}/json`)
      .pipe(first());
  }

  public getUFs() {
    return this.http
      .get<any[]>(
        `https://servicodados.ibge.gov.br/api/v1/localidades/estados`,
        {
          params: { orderBy: 'nome' },
        }
      )
      .pipe(
        delay(2000),
        map((ufs) =>
          ufs.map((uf) => {
            return {
              value: uf.sigla,
              name: uf.sigla,
            } as CatFormListOptions;
          })
        ),
        first()
      );
  }
}
```

{% endtab %}

{% tab title="name.validator.ts" %}

```typescript
import { AbstractControl } from "@angular/forms";
import { CatFormValidatorResponseFactory } from "@catrx/ui/form";

export function nameValidator(control: AbstractControl) {
  if (!Number.isNaN(parseInt(control.value))) {
    return CatFormValidatorResponseFactory.generate('Este não é um nome válido.');
  }

  return null;
}
```

{% endtab %}

{% tab title="form-example.component.ts" %}

```typescript
import { Component } from '@angular/core';
import { CatFileInterface } from '@catrx/ui/utils';
import {
  CatFormBehavior,
  CatFormService,
} from '@catrx/ui/form';
import { Subject } from 'rxjs/internal/Subject';
import { PageFormService } from './page-form.service';
import { nameValidator } from './validators/name.validator';

@Component({
  templateUrl: 'form-example.component.html',
  styles: [
    `
      form {
        display: block;
        margin: 15px 20px;
      }
    `,
  ],
})
export class FormExampleComponent {
  config = this.formService
    .build()
    .fieldset(
      'Autopreencher funcionário por arquivo',
      'autofillFormByFile',
      (builder) =>
        builder
          .csv('importEmployee', (builder) =>
            builder
              .setModel({
                filename: 'MODELO_IMPORTACAO_FUNCIONARIO',
                model: { name: '', lastname: '' },
              })
              .onChange((data: CatFileInterface, behavior) => {
                const employee = data?.csvContent?.[0];
                if (employee) {
                  behavior
                    .setValues([
                      {
                        name: 'personData.name',
                        value: employee['name'],
                      },
                      {
                        name: 'personData.lastname',
                        value: employee['lastname'],
                      },
                    ])
                    .send();
                }
              })
              .generate()
          )
          .generate()
    )
    .fieldset('Dados Pessoais', 'personData', (builder) =>
      builder
        .text('Nome', 'name', (builder) =>
          builder
            .setHint('Informe <b>TESTE</b> para desbloquear o sobrenome')
            .grid(3)
            .focus()
            .setRequired()
            .setMinLength(5)
            .setValidators([nameValidator])
            .onChange((value, behavior) => {
              if (value === 'teste') {
                behavior.enableFields(['personData.lastname']);
              } else {
                behavior.disableFields(['personData.lastname']);
              }
              behavior.send();
            })
            .generate()
        )
        .text('Sobrenome', 'lastname', (builder) =>
          builder.grid(3).disabled().setRequired().generate()
        )
        .cpf('CPF', 'cpf', (builder) =>
          builder.grid(3).setRequired().generate()
        )
        .date('Data de Nascimento', 'birthDate', (builder) =>
          builder.grid(3).setMax('2002-01-01').setRequired().generate()
        )
        .email('E-mail', 'email', (builder) => builder.grid(6).generate())
        .url('LinkedIn', 'linkedin', (builder) => builder.grid(6).generate())
        .generate()
    )
    .fieldset('Dados Profissionais', 'employeeData', (builder) =>
      builder
        .fieldset('Habilidades', 'skills', (builder) =>
          builder
            .checkbox('NodeJS', 'nodejs', (builder) => builder.generate())
            .checkbox('PHP', 'php', (builder) => builder.generate())
            .checkbox('Angular', 'angular', (builder) => builder.generate())
            .grid(6)
            .isCheckboxGroup()
            .generate()
        )
        .fieldset('Área', 'workArea', (builder) =>
          builder
            .radio('stack', (builder) =>
              builder
                .setOptions([
                  { name: 'FrontEnd', value: 'frontend' },
                  { name: 'BackEnd', value: 'backend' },
                  { name: 'FullStack', value: 'fullstack' },
                ])
                .setValue('backend')
                .generate()
            )
            .grid(6)
            .isCheckboxGroup()
            .generate()
        )
        .file('curriculum', (builder) =>
          builder
            .setIcon('fa-solid fa-paperclip')
            .setBtnText('Anexe o curriculo aqui')
            .setExtensionsAccept(['.pdf'])
            .setRequired()
            .generate()
        )
        .generate()
    )
    .fieldset('Endereço', 'employeeLocation', (builder) =>
      builder
        .text('CEP', 'cep', (builder) =>
          builder
            .grid(3)
            .setMinLength(8)
            .setMaxLength(8)
            .setRequired()
            .onChange((cep, behavior) =>
              this.pageFormService
                .getAddressByZipCode(cep)
                .subscribe((address) => this.fillAddress(address, behavior))
            )
            .generate()
        )
        .text('Logradouro', 'street', (builder) =>
          builder.grid(6).setRequired().setMaxLength(50).generate()
        )
        .text('Bairro', 'district', (builder) =>
          builder.grid(3).setRequired().setMaxLength(30).generate()
        )
        .text('Complemento', 'complement', (builder) =>
          builder.grid(3).setMaxLength(50).generate()
        )
        .number('Número', 'number', (builder) => builder.grid(2).generate())
        .text('Cidade', 'city', (builder) =>
          builder.grid(4).setRequired().setMaxLength(50).generate()
        )
        .autocomplete('Estado', 'state', (builder) =>
          builder
            .setOptions(this.pageFormService.getUFs())
            .grid(3)
            .setRequired()
            .onChange((value) => console.log(value))
            .generate()
        )
        .generate()
    )
    .fieldset('Empresa Contratante', 'empresaContratante', (builder) =>
      builder
        .text('Razão Social', 'corporateName', (builder) =>
          builder
            .grid(6)
            .setRequired()
            .setMaxLength(50)
            .setValidators([nameValidator])
            .generate()
        )
        .text('Nome Fantasia', 'lastname', (builder) =>
          builder.grid(3).setMaxLength(30).generate()
        )
        .cnpj('CNPJ', 'cnpj', (builder) =>
          builder.grid(3).setRequired().generate()
        )
        .generate()
    )
    .fieldset('Dados do Contrato', 'contractData', (builder) =>
      builder
        .time('Hora de Entrada', 'startTime', (builder) =>
          builder
            .grid(3)
            .setMin('08:00:00')
            .setMax('18:00:00')
            .setRequired()
            .generate()
        )
        .datetime('Data/Hora Admissão', 'contractDate', (builder) =>
          builder
            .grid(3)
            .setMin('2022-12-01 00:00')
            .setMax('2022-12-23 23:59')
            .setRequired()
            .generate()
        )
        .generate()
    )
    .fieldset('Dados Bancários', 'bankData', (builder) =>
      builder
        .number('Código do Banco', 'febrabamCode', (builder) =>
          builder.setRequired().setMin(1).setMax(999).grid(3).generate()
        )
        .number('Agência', 'agency', (builder) =>
          builder.setRequired().setMax(999).grid(3).generate()
        )
        .text('Nº da Conta', 'bankNumber', (builder) =>
          builder.setRequired().setMaxLength(8).grid(3).generate()
        )
        .generate()
    )
    .textarea('Descrição', 'description', (builder) =>
      builder.setMaxLength(1000).generate()
    )
    .onSubmit((data) => console.log(data))
    .generate();

  constructor(
    private formService: CatFormService,
    private pageFormService: PageFormService
  ) {}

  private fillAddress(address: any, behavior: CatFormBehavior) {
    behavior
      .setValues([
        {
          name: 'employeeLocation.street',
          value: address.logradouro,
        },
        {
          name: 'employeeLocation.district',
          value: address.bairro,
        },
        {
          name: 'employeeLocation.complement',
          value: address.complemento,
        },
        {
          name: 'employeeLocation.city',
          value: address.localidade,
        },
        {
          name: 'employeeLocation.state',
          value: address.uf,
        },
      ])
      .send();
  }
}
```

{% endtab %}

{% tab title="form-example.component.html" %}

```html
<form [formGroup]="form.dynamicForm" (submit)="form.submit()">
  <cat-form #form [config]="config">
  </cat-form>

  <button type="submit" class="btn btn-primary btn-sm">Enviar</button>
</form>
```

{% endtab %}
{% endtabs %}

### Overview

{% embed url="<https://cat-ui.igordrangel.com.br/components/form>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://doc.catui.igordrangel.com.br/formulario/formulario-dinamico.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
