validacao_orientada_a_modelo - VWJavascript/Alurapic GitHub Wiki
Para que possamos realizar uma validação baseada em modelo (model-driven form) precisamos realizar alguns ajustes no código do template que escrevemos até agora. O primeiro deles é importarmos o módulo ReactiveFormsModule em AppModule para habilitar essa funcionalidade:
// alurapic/client/app/app.module.ts
// outros imports omitidos
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports: [
BrowserModule,
HttpModule,
PainelModule,
FotoModule,
routing,
FormsModule,
ReactiveFormsModule
],
declarations: [ AppComponent, ListagemComponent, CadastroComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
O segundo passo é remover a declaração da variável local #meuForm. Como ela não existe mais, não temos um valor para usar na diretiva disabled para desabilitar o botão "salvar" caso o formulário esteja inválido. Temporariamente deixaremos um valor vazio:
<!-- código posterior omitido -->
<button type="submit" class="btn btn-primary" [disabled]= " " >Salvar</button>
<!-- código posterior omitido -->
Também precisamos remover a declaração da variável local #titulo. Com sua remoção, também não temos mais um valor para colocar na diretiva ngIf que decide se exibe ou não a mensagem de erro de validação para o usuário. Também vamos deixar seu valor vazio por enquanto:
<form (submit)="cadastrar($event)" class="row">
<div class="col-md-6">
<div class="form-group">
<label>Título</label>
<input
name="titulo"
[(ngModel)]="foto.titulo"
class="form-control" autocomplete="off">
<span *ngIf= " " class="form-control alert-danger">
Título obrigatório
</span>
</div>
<!-- código posterior omitido -->
Precisamos fazer a mesma coisa com a URL!
Agora que fizemos esses pequenos ajustes, vamos criar uma nova propriedade em CadastroComponent que seja do tipo FormGroup. Instâncias de FormGroup podem gerenciar um ou mais inputs de controle. Para isso, precisamos importar a classe do módulo @angular/forms.
// alurapic/client/app/cadastro/cadastro.component.ts
import { Component, Input } from '@angular/core';
import { FotoComponent } from '../foto/foto.component';
import { Http, Headers } from '@angular/http';
import { FormGroup } from '@angular/forms';
@Component({
moduleId: module.id,
selector: 'cadastro',
templateUrl: './cadastro.component.html'
})
export class CadastroComponent {
foto: FotoComponent = new FotoComponent();
http: Http;
meuForm: FormGroup;
constructor(http: Http) {
// restante do código omitido
Agora que vamos associar o atributo do nosso componente meuForm que é um FormGroup ao formulário do nosso template através da diretiva formGroup:
<form [formGroup]="meuForm" (submit)="cadastrar($event)" class="row">
Agora que temos tudo encaixado, vamos construir nosso FormGroup.
Angular nos permite agrupar vários campos (FormControl) dentro de um grupo (FormGroup). Essa maneira de agrupar controles é interessante, porque podemos perguntar ao grupo se ele esta válido (se todos os controles estão válidos) ou se é inválido (se um dos controles for inválido).
Angular possui a classe FormBuilder que nos ajuda a criar uma instância de FormGroup. Vamos importar essa classe e injetá-la no construtor do nosso componente. É por meio do seu método group que criamos uma validação para um ou mais campos:
// alurapic/client/app/cadastro/cadastro.component.ts
import { Component, Input } from '@angular/core';
import { FotoComponent } from '../foto/foto.component';
import { Http, Headers } from '@angular/http';
import { FormGroup, FormBuilder } from '@angular/forms';
@Component({
moduleId: module.id,
selector: 'cadastro',
templateUrl: './cadastro.component.html'
})
export class CadastroComponent {
foto: FotoComponent = new FotoComponent();
http: Http;
meuForm: FormGroup;
constructor(http: Http, fb: FormBuilder) {
this.http = http;
this.meuForm = fb.group({
titulo: ['', /* qual validação usar? */],
url: ['', /* qual validação usar? */],
descricao: ['', /* qual validação usar? */]
});
}
// código posterior omitido
Veja que o método group recebe um objeto JavaScript onde a chave é o identificador do campo e seu valor um array com configurações de validação. Usamos a chave titulo para indicar que estamos validando o campo título e assim por diante. Ainda não indicamos que tipo de validação utilizaremos, mas precisamos ligar o input do template do nosso componente através dessa chave. Fazemos isso através da diretiva formControlName. Alterando nosso template:
<div class="form-group">
<label>Título</label>
<input
name="titulo"
[(ngModel)]="foto.titulo"
formControlName="titulo"
class="form-control" autocomplete="off">
<span *ngIf="meuForm.controls.titulo.invalid" class="form-control alert-danger">
Título obrigatório
</span>
</div>
<div class="form-group">
<label>URL</label>
<input name="url" [(ngModel)]="foto.url" formControlName="url" class="form-control" autocomplete="off">
<span *ngIf="meuForm.controls.url.invalid" class="form-control alert-danger">
URL obrigatória
</span>
</div>
<div class="form-group">
<label>Descrição</label>
<textarea name="descricao" [(ngModel)]="foto.descricao" formControlName="descricao" class="form-control">
</textarea>
</div>
Veja também que para os campos titulo e url voltamos a preencher a condição ngIf, só que dessa vez consultando o elemento dentro do meuForm.controls.
Chegou a hora de definirmos nosso primeiro validador, aquele que torna o preenchimento do campo obrigatório. Para isso, precisamos importar Validators do módulo @angular/forms:
// alurapic/client/app/cadastro/cadastro.component.ts
import { Component, Input } from '@angular/core';
import { FotoComponent } from '../foto/foto.component';
import { Http, Headers } from '@angular/http';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
@Component({
moduleId: module.id,
selector: 'cadastro',
templateUrl: './cadastro.component.html'
})
export class CadastroComponent {
foto: FotoComponent = new FotoComponent();
http: Http;
meuForm: FormGroup;
constructor(http: Http, fb: FormBuilder) {
this.http = http;
this.meuForm = fb.group({
titulo: ['', Validators.required],
url: ['', Validators.required],
descricao: [''],
});
}
// código posterior omitido
Apenas os controles titulo e url serão validados, e ainda assim somos obrigados a adicionar o controle descricao sem nenhum validador. Caso contrário não teremos acesso a esta informação quando formos submeter o formulário.
Por fim, só precisamos de mais uma alteração. Lembra do botão que desabilitamos se o formulários estiver inválido? Ele agora acessará meuForm; não a variável que removemos, mas a propriedade do nosso componente:
<!-- alurapic/client/app/cadastro/cadastro.component.html -->
<!-- código anterior omitido -->
<button type="submit" class="btn btn-primary"
[disabled]="meuForm.invalid">
Salvar
</button>