Modulo FormsModule e Diretiva ngModel em Angular
Nas aplicações web, geralmente utilizamos formulários para interagir com o usuário. Para implementar a funcionalidade dos formulários, os componentes precisam importar o módulo FormsModule
utilizando o parâmetro imports
. Antes de utilizar os formulários nos componentes, é necessário importar o módulo FormsModule
no módulo principal AppModule
, o que permite o uso adequado dos formulários:
import { Component } from "@angular/core";
import { FormsModule } from "@angular/forms";
@Component({
selector: "my-app",
standalone: true,
imports: [FormsModule], // Importa FormsModule para trabalhar com formulários
template: ``,
})
export class AppComponent {}
Além disso, no arquivo de configuração da aplicação (package.json
), o pacote "angular/forms"
deve estar listado entre as dependências utilizadas:
{
"name": "helloapp",
"version": "1.0.0",
"description": "Projeto Angular",
"author": "www.programicio.com",
"scripts": {
// comandos angular cli
},
"dependencies": {
"@angular/forms": "~17.0.0",
// outros pacotes
},
"devDependencies": {
// outros pacotes
}
}
Ao trabalhar com formulários, a diretiva essencial é o NgModel
. Essa diretiva cria um objeto FormControl
baseado no modelo passado e vincula esse modelo ao elemento de formulário gerado. O FormControl
rastreia o valor do modelo, além de ser responsável por validar esse valor e gerenciar a interação com o usuário.
A diretiva NgModel
recebe o modelo passado como uma propriedade de entrada. Podemos usar tanto o binding unidirecional quanto o binding bidirecional.
Se for necessário apenas exibir o valor do modelo no campo de entrada, o binding unidirecional é suficiente:
<input name="title" [ngModel]="title" />
Aqui, um vínculo simples de propriedade é utilizado, onde o modelo é uma propriedade title
definida na classe do componente.
Caso seja necessário acompanhar as alterações nos dados inseridos, utilizamos o binding bidirecional:
<input name="title" [(ngModel)]="title" />
Agora, vamos examinar a aplicação do NgModel
com um exemplo. Consideremos um projeto com uma estrutura básica:
helloapp/ ├── src/ │ ├── app/ │ │ ├── app.component.ts │ ├── main.ts │ ├── index.html ├── angular.json ├── package-lock.json ├── package.json └── tsconfig.json
Aqui está a definição do componente em app.component.ts
:
import { Component } from "@angular/core";
import { FormsModule } from "@angular/forms";
class User {
constructor(public name: string, public age: number, public company: string) {}
}
@Component({
selector: "my-app",
standalone: true,
imports: [FormsModule], // Importa FormsModule para trabalhar com formulários
template: `<div>
<p>
<label>Nome do usuário</label><br />
<input name="name" [(ngModel)]="name" />
</p>
<p>
<label>Idade</label><br />
<input type="number" name="age" [(ngModel)]="age" />
</p>
<p>
<label>Empresa</label><br />
<select name="company" [(ngModel)]="company">
@for(comp of companies; track $index){
<option [value]="comp">
{{ comp }}
</option>
}
</select>
</p>
<button (click)="addUser()">Adicionar</button>
</div>
<div>
<h3>Itens adicionados</h3>
<ul>
@for(u of users; track $index){
<li>{{ u.name }} ({{ u.company }}) - {{ u.age }}</li>
}
</ul>
</div>`,
})
export class AppComponent {
name: string = "";
age: number = 18;
company: string = "";
users: User[] = [];
companies: string[] = ["Apple", "Microsoft", "Google", "Jetbrains"];
addUser() {
this.users.push(new User(this.name, this.age, this.company));
}
}
Aqui, foi definida a classe User
com três propriedades. O componente AppComponent
contém um array de usuários e um array de empresas. No template, foram definidos três campos de entrada. Cada campo possui a diretiva [(ngModel)]
, que define a ligação entre o valor do campo e a propriedade correspondente no componente. O método addUser()
é chamado quando o botão é clicado, adicionando os valores inseridos ao array users
.
No final do template, os dados adicionados são exibidos na página:
Os três campos de entrada estão vinculados a valores separados que existem independentemente. No entanto, é possível ir além e definir um modelo que encapsule esses valores, como mostrado abaixo:
import { Component } from "@angular/core";
import { FormsModule } from "@angular/forms";
class User {
constructor(public name: string, public age: number, public company: string) {}
}
@Component({
selector: "my-app",
standalone: true,
imports: [FormsModule], // Importa FormsModule para trabalhar com formulários
template: `<div>
<p>
<label>Nome do usuário</label><br />
<input name="name" [(ngModel)]="newUser.name" />
</p>
<p>
<label>Idade</label><br />
<input type="number" name="age" [(ngModel)]="newUser.age" />
</p>
<p>
<label>Empresa</label><br />
<select name="company" [(ngModel)]="newUser.company">
@for(comp of companies; track $index){
<option [value]="comp">
{{ comp }}
</option>
}
</select>
</p>
<button (click)="addUser()">Adicionar</button>
</div>
<div>
<h3>Itens adicionados</h3>
<ul>
@for(u of users; track $index){
<li>{{ u.name }} ({{ u.company }}) - {{ u.age }}</li>
}
</ul>
</div>`,
})
export class AppComponent {
newUser = new User("", 18, "Google");
users: User[] = [];
companies: string[] = ["Apple", "Microsoft", "Google", "Jetbrains"];
addUser() {
this.users.push({ ...this.newUser });
}
}
Aqui, foi criada a variável newUser
, cujas propriedades estão vinculadas aos campos de entrada. Um ponto importante é que, ao adicionar um novo objeto ao array users
, não é passada a referência direta de newUser
. Em vez disso, é criado um novo objeto com os valores de newUser
, evitando que alterações futuras afetem o objeto já adicionado. O resultado final é o mesmo do exemplo anterior.