Este tutorial mostra como criar um formulário template-driven. Os elementos de controle no formulário são vinculados a propriedades de dados que possuem validação de entrada. A validação de entrada ajuda a manter a integridade dos dados e o estilo melhora a experiência do usuário.
Formulários template-driven usam vinculação de dados bidirecional para atualizar o modelo de dados no component conforme as alterações são feitas no template e vice-versa.
Template vs Reactive forms
Angular suporta duas abordagens de design para formulários interativos. Formulários template-driven permitem que você use directives específicas de formulário em seu template Angular. Formulários reactive fornecem uma abordagem orientada a modelo para construção de formulários.
Formulários template-driven são uma ótima escolha para formulários pequenos ou simples, enquanto formulários reactive são mais escaláveis e adequados para formulários complexos. Para uma comparação das duas abordagens, veja Escolhendo uma abordagem
Você pode construir praticamente qualquer tipo de formulário com um template Angular — formulários de login, formulários de contato e praticamente qualquer formulário de negócios. Você pode dispor os controles de forma criativa e vinculá-los aos dados no seu modelo de objeto. Você pode especificar regras de validação e exibir erros de validação, permitir condicionalmente entrada de controles específicos, acionar feedback visual integrado e muito mais.
Objetivos
Este tutorial ensina como fazer o seguinte:
- Construir um formulário Angular com um component e template
- Usar
ngModelpara criar vinculações de dados bidirecionais para leitura e escrita de valores de controle de entrada - Fornecer feedback visual usando classes CSS especiais que rastreiam o estado dos controles
- Exibir erros de validação aos usuários e permitir condicionalmente entrada de controles de formulário com base no status do formulário
- Compartilhar informações entre elementos HTML usando variáveis de referência de template
Construir um formulário template-driven
Formulários template-driven dependem de directives definidas no FormsModule.
| Directives | Detalhes |
|---|---|
NgModel |
Reconcilia mudanças de valor no elemento de formulário anexado com mudanças no modelo de dados, permitindo que você responda à entrada do usuário com validação de entrada e tratamento de erros. |
NgForm |
Cria uma instância FormGroup de nível superior e a vincula a um elemento <form> para rastrear o valor agregado do formulário e o status de validação. Assim que você importa o FormsModule, esta directive se torna ativa por padrão em todas as tags <form>. Você não precisa adicionar um seletor especial. |
NgModelGroup |
Cria e vincula uma instância FormGroup a um elemento DOM. |
Visão geral das etapas
No decorrer deste tutorial, você vincula um formulário de exemplo aos dados e lida com a entrada do usuário usando as seguintes etapas.
- Construir o formulário básico.
- Definir um modelo de dados de exemplo
- Incluir a infraestrutura necessária, como o
FormsModule
- Vincular controles de formulário a propriedades de dados usando a directive
ngModele a sintaxe de vinculação de dados bidirecional.- Examinar como
ngModelrelata estados de controle usando classes CSS - Nomear controles para torná-los acessíveis ao
ngModel
- Examinar como
- Rastrear a validade de entrada e o status do controle usando
ngModel.- Adicionar CSS personalizado para fornecer feedback visual sobre o status
- Mostrar e ocultar mensagens de erro de validação
- Responder a um evento de clique de botão HTML nativo adicionando aos dados do modelo.
- Lidar com o envio do formulário usando a propriedade de output
ngSubmitdo formulário.- Desabilitar o botão Submit até que o formulário seja válido
- Após o envio, trocar o formulário concluído por conteúdo diferente na página
Construir o formulário
- O aplicativo de exemplo fornecido cria a classe
Actorque define o modelo de dados refletido no formulário.
actor.ts
export class Actor { constructor( public id: number, public name: string, public skill: string, public studio?: string, ) {}}
O layout e os detalhes do formulário são definidos na classe
ActorFormComponent.actor-form.component.ts (v1)
import {Component} from '@angular/core';import {Actor} from '../actor';import {FormsModule} from '@angular/forms';import {JsonPipe} from '@angular/common';@Component({ selector: 'app-actor-form', templateUrl: './actor-form.component.html', imports: [FormsModule, JsonPipe],})export class ActorFormComponent { skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting']; model = new Actor(18, 'Tom Cruise', this.skills[3], 'CW Productions'); submitted = false; onSubmit() { this.submitted = true; } newActor() { this.model = new Actor(42, '', ''); } heroine(): Actor { const myActress = new Actor(42, 'Marilyn Monroe', 'Singing'); console.log('My actress is called ' + myActress.name); // "My actress is called Marilyn" return myActress; } //////// NOT SHOWN IN DOCS //////// // Reveal in html: // Name via form.controls = {{showFormControls(actorForm)}} showFormControls(form: any) { return form && form.controls.name && form.controls.name.value; // Tom Cruise } /////////////////////////////}O valor do
selectordo component "app-actor-form" significa que você pode colocar este formulário em um template pai usando a tag<app-actor-form>.O código a seguir cria uma nova instância de actor, para que o formulário inicial possa mostrar um actor de exemplo.
import {Component} from '@angular/core';import {Actor} from '../actor';import {FormsModule} from '@angular/forms';import {JsonPipe} from '@angular/common';@Component({ selector: 'app-actor-form', templateUrl: './actor-form.component.html', imports: [FormsModule, JsonPipe],})export class ActorFormComponent { skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting']; model = new Actor(18, 'Tom Cruise', this.skills[3], 'CW Productions'); submitted = false; onSubmit() { this.submitted = true; } newActor() { this.model = new Actor(42, '', ''); } heroine(): Actor { const myActress = new Actor(42, 'Marilyn Monroe', 'Singing'); console.log('My actress is called ' + myActress.name); // "My actress is called Marilyn" return myActress; } //////// NOT SHOWN IN DOCS //////// // Reveal in html: // Name via form.controls = {{showFormControls(actorForm)}} showFormControls(form: any) { return form && form.controls.name && form.controls.name.value; // Tom Cruise } /////////////////////////////}Esta demonstração usa dados fictícios para
modeleskills. Em um aplicativo real, você injetaria um service de dados para obter e salvar dados reais, ou exporia essas propriedades como inputs e outputs.O component habilita o recurso de Forms importando o módulo
FormsModule.import {Component} from '@angular/core';import {Actor} from '../actor';import {FormsModule} from '@angular/forms';import {JsonPipe} from '@angular/common';@Component({ selector: 'app-actor-form', templateUrl: './actor-form.component.html', imports: [FormsModule, JsonPipe],})export class ActorFormComponent { skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting']; model = new Actor(18, 'Tom Cruise', this.skills[3], 'CW Productions'); submitted = false; onSubmit() { this.submitted = true; } newActor() { this.model = new Actor(42, '', ''); } heroine(): Actor { const myActress = new Actor(42, 'Marilyn Monroe', 'Singing'); console.log('My actress is called ' + myActress.name); // "My actress is called Marilyn" return myActress; } //////// NOT SHOWN IN DOCS //////// // Reveal in html: // Name via form.controls = {{showFormControls(actorForm)}} showFormControls(form: any) { return form && form.controls.name && form.controls.name.value; // Tom Cruise } /////////////////////////////}O formulário é exibido no layout do aplicativo definido pelo template do component raiz.
src/app/app.component.html
<app-actor-form />O template inicial define o layout para um formulário com dois grupos de formulário e um botão de envio. Os grupos de formulário correspondem a duas propriedades do modelo de dados Actor, name e studio. Cada grupo tem um rótulo e uma caixa para entrada do usuário.
- O elemento de controle
<input>de Name tem o atributo HTML5required - O elemento de controle
<input>de Studio não tem porquestudioé opcional
O botão Submit tem algumas classes nele para estilização. Neste ponto, o layout do formulário é todo HTML5 simples, sem vinculações ou directives.
- O elemento de controle
O formulário de exemplo usa algumas classes de estilo do Twitter Bootstrap:
container,form-group,form-controlebtn. Para usar esses estilos, a folha de estilo do aplicativo importa a biblioteca.
src/styles.css
@import url('https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css');
- O formulário requer que a habilidade de um actor seja escolhida de uma lista predefinida de
skillsmantida internamente emActorFormComponent. O loop@fordo Angular itera sobre os valores de dados para preencher o elemento<select>.
actor-form.component.html (skills)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Name is required </div> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor Form</h1> <form> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for(skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
Se você executar o aplicativo agora, verá a lista de habilidades no controle de seleção. Os elementos de entrada ainda não estão vinculados a valores de dados ou eventos, portanto ainda estão em branco e não têm comportamento.
Vincular controles de entrada a propriedades de dados
O próximo passo é vincular os controles de entrada às propriedades Actor correspondentes com vinculação de dados bidirecional, para que eles respondam à entrada do usuário atualizando o modelo de dados e também respondam a mudanças programáticas nos dados atualizando a exibição.
A directive ngModel declarada no FormsModule permite vincular controles em seu formulário template-driven a propriedades em seu modelo de dados.
Quando você inclui a directive usando a sintaxe para vinculação de dados bidirecional, [(ngModel)], o Angular pode rastrear o valor e a interação do usuário com o controle e manter a view sincronizada com o modelo.
- Edite o arquivo de template
actor-form.component.html. - Encontre a tag
<input>ao lado do rótulo Name. - Adicione a directive
ngModel, usando a sintaxe de vinculação de dados bidirecional[(ngModel)]="...".
actor-form.component.html (excerpt)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Name is required </div> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor Form</h1> <form> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for(skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
HELPFUL: Este exemplo tem uma interpolação de diagnóstico temporária após cada tag de entrada, {{model.name}}, para mostrar o valor de dados atual da propriedade correspondente. O comentário lembra você de remover as linhas de diagnóstico quando terminar de observar a vinculação de dados bidirecional em funcionamento.
Acessar o status geral do formulário
Quando você importou o FormsModule em seu component, o Angular criou e anexou automaticamente uma directive NgForm à tag <form> no template (porque NgForm tem o seletor form que corresponde aos elementos <form>).
Para obter acesso ao NgForm e ao status geral do formulário, declare uma variável de referência de template.
Edite o arquivo de template
actor-form.component.html.Atualize a tag
<form>com uma variável de referência de template,#actorForm, e defina seu valor da seguinte forma.actor-form.component.html (excerpt)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Name is required </div> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor Form</h1> <form> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for(skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>A variável de template
actorFormagora é uma referência à instância da directiveNgFormque governa o formulário como um todo.Execute o aplicativo.
Comece a digitar na caixa de entrada Name.
Conforme você adiciona e exclui caracteres, pode vê-los aparecer e desaparecer do modelo de dados.
A linha de diagnóstico que mostra valores interpolados demonstra que os valores estão realmente fluindo da caixa de entrada para o modelo e de volta novamente.
Nomear elementos de controle
Quando você usa [(ngModel)] em um elemento, deve definir um atributo name para esse elemento.
O Angular usa o nome atribuído para registrar o elemento com a directive NgForm anexada ao elemento pai <form>.
O exemplo adicionou um atributo name ao elemento <input> e o definiu como "name", o que faz sentido para o nome do actor.
Qualquer valor único serve, mas usar um nome descritivo é útil.
- Adicione vinculações
[(ngModel)]e atributosnamesimilares a Studio e Skill. - Agora você pode remover as mensagens de diagnóstico que mostram valores interpolados.
- Para confirmar que a vinculação de dados bidirecional funciona para todo o modelo de actor, adicione uma nova vinculação de texto com o pipe
jsonno topo do template do component, que serializa os dados para uma string.
Após essas revisões, o template do formulário deve se parecer com o seguinte:
actor-form.component.html (excerpt)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Name is required </div> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor Form</h1> <form> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for(skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
Você notará que:
Cada elemento
<input>tem uma propriedadeid. Isso é usado pelo atributofordo elemento<label>para corresponder o rótulo ao seu controle de entrada. Este é um recurso HTML padrão.Cada elemento
<input>também tem a propriedadenamenecessária que o Angular usa para registrar o controle com o formulário.
Quando você tiver observado os efeitos, pode excluir a vinculação de texto {{ model | json }}.
Rastrear estados do formulário
O Angular aplica a classe ng-submitted aos elementos form após o formulário ter sido enviado. Esta classe pode ser usada para alterar o estilo do formulário após ele ter sido enviado.
Rastrear estados do controle
Adicionar a directive NgModel a um controle adiciona nomes de classe ao controle que descrevem seu estado.
Essas classes podem ser usadas para alterar o estilo de um controle com base em seu estado.
A tabela a seguir descreve os nomes de classe que o Angular aplica com base no estado do controle.
| Estados | Classe se verdadeiro | Classe se falso |
|---|---|---|
| O controle foi visitado. | ng-touched |
ng-untouched |
| O valor do controle foi alterado. | ng-dirty |
ng-pristine |
| O valor do controle é válido. | ng-valid |
ng-invalid |
O Angular também aplica a classe ng-submitted aos elementos form após o envio,
mas não aos controles dentro do elemento form.
Você usa essas classes CSS para definir os estilos para seu controle com base em seu status.
Observar estados do controle
Para ver como as classes são adicionadas e removidas pelo framework, abra as ferramentas de desenvolvedor do navegador e inspecione o elemento <input> que representa o nome do actor.
Usando as ferramentas de desenvolvedor do seu navegador, encontre o elemento
<input>que corresponde à caixa de entrada Name. Você pode ver que o elemento tem várias classes CSS além de "form-control".Quando você o abre pela primeira vez, as classes indicam que ele tem um valor válido, que o valor não foi alterado desde a inicialização ou redefinição, e que o controle não foi visitado desde a inicialização ou redefinição.
Execute as seguintes ações na caixa
<input>de Name e observe quais classes aparecem.Olhe mas não toque. As classes indicam que está intocado, pristine e válido.
Clique dentro da caixa de nome, depois clique fora dela. O controle foi visitado agora, e o elemento tem a classe
ng-touchedem vez da classeng-untouched.Adicione barras ao final do nome. Agora está touched e dirty.
Apague o nome. Isso torna o valor inválido, então a classe
ng-invalidsubstitui a classeng-valid.
Criar feedback visual para estados
O par ng-valid/ng-invalid é particularmente interessante, porque você quer enviar um
sinal visual forte quando os valores são inválidos.
Você também quer marcar campos obrigatórios.
Você pode marcar campos obrigatórios e dados inválidos ao mesmo tempo com uma barra colorida à esquerda da caixa de entrada.
Para alterar a aparência dessa forma, execute as seguintes etapas.
- Adicione definições para as classes CSS
ng-*. - Adicione essas definições de classe a um novo arquivo
forms.css. - Adicione o novo arquivo ao projeto como irmão de
index.html:
src/assets/forms.css
.ng-valid[required], .ng-valid.required { border-left: 5px solid #42A948; /* green */}.ng-invalid:not(form) { border-left: 5px solid #a94442; /* red */}
- No arquivo
index.html, atualize a tag<head>para incluir a nova folha de estilo.
src/index.html (styles)
<!DOCTYPE html><html lang="en"> <head> <title>Hero Form</title> <base href="/"> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://unpkg.com/bootstrap@3.3.7/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="assets/forms.css"> </head> <body> <app-root></app-root> </body></html>
Mostrar e ocultar mensagens de erro de validação
A caixa de entrada Name é obrigatória e limpá-la deixa a barra vermelha. Isso indica que algo está errado, mas o usuário não sabe o que está errado ou o que fazer a respeito. Você pode fornecer uma mensagem útil verificando e respondendo ao estado do controle.
A caixa de seleção Skill também é obrigatória, mas não precisa desse tipo de tratamento de erro porque a caixa de seleção já restringe a seleção a valores válidos.
Para definir e mostrar uma mensagem de erro quando apropriado, execute as seguintes etapas.
-
Adicionar uma referência local à entrada
Estenda a tag
inputcom uma variável de referência de template que você pode usar para acessar o controle Angular da caixa de entrada de dentro do template. No exemplo, a variável é#name="ngModel".A variável de referência de template (
#name) é definida como"ngModel"porque esse é o valor da propriedadeNgModel.exportAs. Esta propriedade diz ao Angular como vincular uma variável de referência a uma directive. -
Adicionar a mensagem de erro
Adicione um
<div>que contém uma mensagem de erro adequada. -
Tornar a mensagem de erro condicional
Mostre ou oculte a mensagem de erro vinculando propriedades do controle
nameà propriedadehiddendo elemento<div>da mensagem. -
Adicionar uma mensagem de erro condicional ao name
Adicione uma mensagem de erro condicional à caixa de entrada
name, como no exemplo a seguir.actor-form.component.html (excerpt)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Name is required </div> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor Form</h1> <form> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for(skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
actor-form.component.html (hidden-error-msg)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Name is required </div> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor Form</h1> <form> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for(skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
Neste exemplo, você oculta a mensagem quando o controle está válido ou pristine.
Pristine significa que o usuário não alterou o valor desde que foi exibido neste formulário.
Se você ignorar o estado pristine, ocultará a mensagem apenas quando o valor for válido.
Se você chegar neste component com um novo actor em branco ou um actor inválido, verá a mensagem de erro imediatamente, antes de ter feito qualquer coisa.
Você pode querer que a mensagem seja exibida apenas quando o usuário fizer uma alteração inválida.
Ocultar a mensagem enquanto o controle está no estado pristine alcança esse objetivo.
Você verá a importância dessa escolha quando adicionar um novo actor ao formulário na próxima etapa.
Adicionar um novo actor
Este exercício mostra como você pode responder a um evento de clique de botão HTML nativo adicionando aos dados do modelo. Para permitir que os usuários do formulário adicionem um novo actor, você adicionará um botão New Actor que responde a um evento de clique.
- No template, coloque um elemento
<button>"New Actor" na parte inferior do formulário. - No arquivo do component, adicione o método de criação de actor ao modelo de dados de actor.
actor-form.component.ts (New Actor method)
import {Component} from '@angular/core';import {Actor} from '../actor';import {FormsModule} from '@angular/forms';import {JsonPipe} from '@angular/common';@Component({ selector: 'app-actor-form', templateUrl: './actor-form.component.html', imports: [FormsModule, JsonPipe],})export class ActorFormComponent { skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting']; model = new Actor(18, 'Tom Cruise', this.skills[3], 'CW Productions'); submitted = false; onSubmit() { this.submitted = true; } newActor() { this.model = new Actor(42, '', ''); } heroine(): Actor { const myActress = new Actor(42, 'Marilyn Monroe', 'Singing'); console.log('My actress is called ' + myActress.name); // "My actress is called Marilyn" return myActress; } //////// NOT SHOWN IN DOCS //////// // Reveal in html: // Name via form.controls = {{showFormControls(actorForm)}} showFormControls(form: any) { return form && form.controls.name && form.controls.name.value; // Tom Cruise } /////////////////////////////}
- Vincule o evento de clique do botão a um método de criação de actor,
newActor().
actor-form.component.html (New Actor button)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Name is required </div> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor Form</h1> <form> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for(skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
Execute o aplicativo novamente e clique no botão New Actor.
O formulário é limpo e as barras obrigatórias à esquerda da caixa de entrada ficam vermelhas, indicando propriedades
nameeskillinválidas. Observe que as mensagens de erro estão ocultas. Isso ocorre porque o formulário está pristine; você ainda não alterou nada.Digite um nome e clique em New Actor novamente.
Agora o aplicativo exibe uma mensagem de erro
Name is required, porque a caixa de entrada não está mais pristine. O formulário lembra que você digitou um nome antes de clicar em New Actor.Para restaurar o estado pristine dos controles do formulário, limpe todos os flags imperativamente chamando o método
reset()do formulário após chamar o métodonewActor().actor-form.component.html (Reset the form)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Name is required </div> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor Form</h1> <form> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for(skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>Agora clicar em New Actor redefine tanto o formulário quanto seus flags de controle.
Enviar o formulário com ngSubmit
O usuário deve ser capaz de enviar este formulário depois de preenchê-lo.
O botão Submit na parte inferior do formulário não faz nada por si só, mas aciona um evento de envio de formulário por causa de seu tipo (type="submit").
Para responder a este evento, execute as seguintes etapas.
-
Escutar ngOnSubmit
Vincule a propriedade de evento
ngSubmitdo formulário ao métodoonSubmit()do component actor-form.actor-form.component.html (ngSubmit)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Name is required </div> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor Form</h1> <form> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for(skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div> -
Vincular a propriedade disabled
Use a variável de referência de template,
#actorFormpara acessar o formulário que contém o botão Submit e criar uma vinculação de evento.Você vinculará a propriedade do formulário que indica sua validade geral à propriedade
disableddo botão Submit.actor-form.component.html (submit-button)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Name is required </div> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor Form</h1> <form> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for(skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div> -
Executar o aplicativo
Observe que o botão está habilitado — embora ainda não faça nada útil.
-
Excluir o valor Name
Isso viola a regra "obrigatória", então exibe a mensagem de erro — e observe que também desabilita o botão Submit.
Você não precisou conectar explicitamente o estado habilitado do botão à validade do formulário. O
FormsModulefez isso automaticamente quando você definiu uma variável de referência de template no elemento de formulário aprimorado, depois referenciou essa variável no controle do botão.
Responder ao envio do formulário
Para mostrar uma resposta ao envio do formulário, você pode ocultar a área de entrada de dados e exibir outra coisa em seu lugar.
-
Encapsular o formulário
Envolva todo o formulário em um
<div>e vincule sua propriedadehiddenà propriedadeActorFormComponent.submitted.actor-form.component.html (excerpt)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Name is required </div> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor Form</h1> <form> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for(skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>O formulário principal está visível desde o início porque a propriedade
submittedé false até que você envie o formulário, como este fragmento doActorFormComponentmostra:actor-form.component.ts (submitted)
import {Component} from '@angular/core';import {Actor} from '../actor';import {FormsModule} from '@angular/forms';import {JsonPipe} from '@angular/common';@Component({ selector: 'app-actor-form', templateUrl: './actor-form.component.html', imports: [FormsModule, JsonPipe],})export class ActorFormComponent { skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting']; model = new Actor(18, 'Tom Cruise', this.skills[3], 'CW Productions'); submitted = false; onSubmit() { this.submitted = true; } newActor() { this.model = new Actor(42, '', ''); } heroine(): Actor { const myActress = new Actor(42, 'Marilyn Monroe', 'Singing'); console.log('My actress is called ' + myActress.name); // "My actress is called Marilyn" return myActress; } //////// NOT SHOWN IN DOCS //////// // Reveal in html: // Name via form.controls = {{showFormControls(actorForm)}} showFormControls(form: any) { return form && form.controls.name && form.controls.name.value; // Tom Cruise } /////////////////////////////}Quando você clica no botão Submit, o flag
submittedse torna true e o formulário desaparece. -
Adicionar o estado submitted
Para mostrar outra coisa enquanto o formulário está no estado submitted, adicione o seguinte HTML abaixo do novo wrapper
<div>.actor-form.component.html (excerpt)
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Name is required </div> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor Form</h1> <form> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for(skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>Este
<div>, que mostra um actor somente leitura com vinculações de interpolação, aparece apenas enquanto o component está no estado submitted.A exibição alternativa inclui um botão Edit cujo evento de clique está vinculado a uma expressão que limpa o flag
submitted. -
Testar o botão Edit
Clique no botão Edit para alternar a exibição de volta para o formulário editável.
Resumo
O formulário Angular discutido nesta página aproveita os seguintes recursos do framework para fornecer suporte para modificação de dados, validação e muito mais.
- Um template de formulário HTML do Angular
- Uma classe component de formulário com um decorator
@Component - Manipulação de envio de formulário vinculando à propriedade de evento
NgForm.ngSubmit - Variáveis de referência de template como
#actorForme#name - Sintaxe
[(ngModel)]para vinculação de dados bidirecional - O uso de atributos
namepara validação e rastreamento de alteração de elemento de formulário - A propriedade
validda variável de referência em controles de entrada indica se um controle é válido ou deve mostrar mensagens de erro - Controlar o estado habilitado do botão Submit vinculando à validade do
NgForm - Classes CSS personalizadas que fornecem feedback visual aos usuários sobre controles que não são válidos
Aqui está o código para a versão final do aplicativo:
actor-form.component.ts
import {Component} from '@angular/core';import {Actor} from '../actor';import {FormsModule} from '@angular/forms';import {JsonPipe} from '@angular/common';@Component({ selector: 'app-actor-form', templateUrl: './actor-form.component.html', imports: [FormsModule, JsonPipe],})export class ActorFormComponent { skills = ['Method Acting', 'Singing', 'Dancing', 'Swordfighting']; model = new Actor(18, 'Tom Cruise', this.skills[3], 'CW Productions'); submitted = false; onSubmit() { this.submitted = true; } newActor() { this.model = new Actor(42, '', ''); } heroine(): Actor { const myActress = new Actor(42, 'Marilyn Monroe', 'Singing'); console.log('My actress is called ' + myActress.name); // "My actress is called Marilyn" return myActress; } //////// NOT SHOWN IN DOCS //////// // Reveal in html: // Name via form.controls = {{showFormControls(actorForm)}} showFormControls(form: any) { return form && form.controls.name && form.controls.name.value; // Tom Cruise } /////////////////////////////}
actor-form.component.html
<div class="container"> <div [hidden]="submitted"> <h1>Actor Form</h1> <form (ngSubmit)="onSubmit()" #actorForm="ngForm"> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel"> <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> Name is required </div> </div> <div class="form-group"> <label for="studio">Studio Affiliation</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill" #skill="ngModel"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> <div [hidden]="skill.valid || skill.pristine" class="alert alert-danger"> skill is required </div> </div> <button type="submit" class="btn btn-success" [disabled]="!actorForm.form.valid">Submit</button> <button type="button" class="btn btn-default" (click)="newActor(); actorForm.reset()">New Actor</button> <em>with</em> reset <button type="button" class="btn btn-default" (click)="newActor()">New Actor</button> <em>without</em> reset <!-- NOT SHOWN IN DOCS --> <div> <hr> Name via form.controls = {{ showFormControls(actorForm) }} </div> <!-- - --> </form> </div> <div [hidden]="!submitted"> <h2>You submitted the following:</h2> <div class="row"> <div class="col-xs-3">Name</div> <div class="col-xs-9">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Studio</div> <div class="col-xs-9">{{ model.studio }}</div> </div> <div class="row"> <div class="col-xs-3">Skill</div> <div class="col-xs-9">{{ model.skill }}</div> </div> <br> <button type="button" class="btn btn-primary" (click)="submitted=false"> Edit </button> </div></div><!-- ==================================================== --> <div> <form> <!-- ... all of the form ... --> </form> </div><!-- ==================================================== --><hr><style> .no-style .ng-valid { border-left: 1px solid #CCC} .no-style .ng-invalid { border-left: 1px solid #CCC}</style><div class="no-style" style="margin-left: 4px"> <div class="container"> <h1>Actor Form</h1> <form> <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required> @for(skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- ==================================================== --> <hr> <div class="container"> <h1>Actor Form</h1> <form #actorForm="ngForm"> {{ model | json }} <div class="form-group"> <label for="name">Name</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="studio">Studio</label> <input type="text" class="form-control" id="studio" [(ngModel)]="model.studio" name="studio"> </div> <div class="form-group"> <label for="skill">Skill</label> <select class="form-control" id="skill" required [(ngModel)]="model.skill" name="skill"> @for (skill of skills; track $index) { <option [value]="skill">{{ skill }}</option> } </select> </div> <button type="submit" class="btn btn-success">Submit</button> </form> </div> <!-- EXTRA MATERIAL FOR DOCUMENTATION --> <hr> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> TODO: remove this: {{ model.name}} <hr> <input type="text" class="form-control" id="name" required [ngModel]="model.name" name="name" (ngModelChange)="model.name = $event"> TODO: remove this: {{ model.name}}</div>
actor.ts
export class Actor { constructor( public id: number, public name: string, public skill: string, public studio?: string, ) {}}
app.component.html
<app-actor-form />
app.component.ts
import {Component} from '@angular/core';import {ActorFormComponent} from './actor-form/actor-form.component';@Component({ selector: 'app-root', templateUrl: './app.component.html', imports: [ActorFormComponent],})export class AppComponent {}
main.ts
import {bootstrapApplication} from '@angular/platform-browser';import {AppComponent} from './app/app.component';import {provideZoneChangeDetection} from '@angular/core';bootstrapApplication(AppComponent, { providers: [provideZoneChangeDetection({eventCoalescing: true})],}).catch((err) => console.error(err));