Для взаимодействия с пользователем в веб-приложениях, как правило применяются формы. Для работы с функциональностью форм компоненты импортируют модуль FormsModule с помощью параметра imports:< Angular прежде чем использовать формы в компонентах, нам надо импортировать в главном модуле AppModule модуль FormsModule, который позволяет работать с формами:
import { Component} from "@angular/core";
import { FormsModule } from "@angular/forms";
@Component({
selector: "my-app",
imports: [FormsModule], // для работы с формами импортируем FormsModule
template: ``
})
export class AppComponent{ }
Кроме того, в файле конфигурации приложения package.json среди списка используемых зависимостей должен быть указан пакет "angular/forms":
{
"name": "helloapp",
"version": "1.0.0",
"description": "First Angular Project",
"author": "Eugene Popov metanit.com",
"scripts": {
// команды angular cli
},
"dependencies": {
"@angular/forms": "~21.0.0",
// остальные пакеты
},
"devDependencies": {
// остальные пакеты
}
}
При работе с формами ключевым моментом является использование директивы NgModel.
Эта директива с помощью переданной модели создает объект FormControl и привязывает эту модель к созданному элементу формы.
Объект FormControl отслеживает значение модели, а также отвечает за валидацию этого значения и взаимодействие с пользователем.
Данная директива принимает переданную ей модель в качестве входного свойства. Причем мы можем использовать как однонаправленную, так и двунаправленную привязку.
Если нам надо просто вывести значение модели в поле ввода, то можно ограничиться и однонаправленной привязкой:
<input name="title" [ngModel]="title" />
Это обычная привязка свойства, где в качестве модели используется некоторое свойство title, определенное в классе компонента.
Если нам надо отслеживать изменение введенных данных, то мы можем использовать двунаправленную привязку:
<input name="title" [(ngModel)]="title" />
Рассмотрим применение NgModel на примере. Возьмем проект с базовой структурой:
Определим в файле 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",
imports: [FormsModule], // для работы с формами импортируем FormsModule
template: `<div>
<p>
<label>Имя пользователя</label><br>
<input name="name" [(ngModel)]="name" />
</p>
<p>
<label>Возраст</label><br>
<input type="number" name="age" [(ngModel)]="age" />
</p>
<p>
<label>Место работы</label><br>
<select name="company" [(ngModel)]="company">
@for(comp of companies; track $index){
<option [value]="comp">
{{comp}}
</option>
}
</select>
</p>
<button (click)="addUser()">Добавить</button>
</div>
<div>
<h3>Добавленные элементы</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));
}
}
Для представления данных здесь определен класс User, в котором есть три свойства. Класс компонента содержит массив объектов User.
С помощью метода addUser() в этот массив добавляется новый объект.
Для добавления данных в шаблоне определены три поля ввода. В каждом поле определены директивы типа [(ngModel)]="namee".
Тем самым фактически определяются некоторые значения, которые привязаны к этим полям. В обработчике нажатия кнопки вызывается метод
addUser(), в который передаются эти значения.
В конце шаблона добавленные данные из массива users выводятся на страницу:
Все три поля привязаны к отдельным значениям, которые существуют сами по себе. Но мы можем пойти дальше и определить для формы ввода отдельную модель, которая будет инкапсулировать эти значения:
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",
imports: [FormsModule], // для работы с формами импортируем FormsModule
template: `<div>
<p>
<label>Имя пользователя</label><br>
<input name="name" [(ngModel)]="newUser.name" />
</p>
<p>
<label>Возраст</label><br>
<input type="number" name="age" [(ngModel)]="newUser.age" />
</p>
<p>
<label>Место работы</label><br>
<select name="company" [(ngModel)]="newUser.company">
@for(comp of companies; track $index){
<option [value]="comp">
{{comp}}
</option>
}
</select>
</p>
<button (click)="addUser()">Добавить</button>
</div>
<div>
<h3>Добавленные элементы</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});
}
}
Для полей ввода здесь создана отдельная переменная newUser, к свойствам которой привязаны поля ввода. Стоит также обратить внимание на то, как добавляется новый объект в массив users - здесь не добавляется напрямую переменная newUser, а создается отдельный объект, который инициализируется значениями из переменной newUser. А в остальном результат будет тем же, что и в предыдущем примере.