Для взаимодействия с пользователем в веб-приложениях, как правило применяются формы. Для работы с функциональностью форм компоненты импортируют модуль FormsModule с помощью параметра imports:< Angular прежде чем использовать формы в компонентах, нам надо импортировать в главном модуле AppModule модуль FormsModule, который позволяет работать с формами:
import { Component} from "@angular/core"; import { FormsModule } from "@angular/forms"; @Component({ selector: "my-app", standalone: true, imports: [FormsModule], // для работы с формами импортируем FormsModule template: `` }) export class AppComponent{ }
Кроме того, в файле конфигурации приложения package.json среди списка используемых зависимостей должен быть указан пакет "angular/forms":
{ "name": "helloapp", "version": "1.0.0", "description": "First Angular 17 Project", "author": "Eugene Popov metanit.com", "scripts": { // команды angular cli }, "dependencies": { "@angular/forms": "~17.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", standalone: true, 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", standalone: true, 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. А в остальном результат будет тем же, что и в предыдущем примере.