Ввод пользователя
Ввод пользователя запускает события DOM. Мы прослушиваем эти события с помощью привязок событий, которые направляют обновлённые значения обратно в наши компоненты и модели.
Действия пользователя, такие как щелчок по ссылке, нажатие кнопки и ввод текста, генерируют события DOM. На этой странице объясняется, как привязать эти события к обработчикам событий компонента, используя синтаксис привязки событий Angular.
Запустить демонстрационный пример.
Привязка к событиям ввода пользователя
Вы можете использовать привязки событий Angular, чтобы реагировать на любые события DOM. Многие события DOM запускаются при вводе пользователя. Привязка к этим событиям предоставляет способ получения ввода от пользователя.
Чтобы привязаться к событию DOM, заключите имя события DOM в скобки и назначьте ему строковое выражение шаблона.
Следующий пример демонстрирует привязку события, реализующую обработчик клика:
<button (click)="onClickMe()">Click me!</button>
Символ (click) слева от знака равенства определяет событие клика по кнопке как цель привязки. Текст в кавычках справа от знака равенства является выражением шаблона, которое реагирует на событие клика, вызывая метод компонента onClickMe.
При написании привязки следует учитывать контекст выполнения выражения шаблона. Идентификаторы в выражении шаблона относятся к определённому объекту контекста, обычно к компоненту Angular, управляющему шаблоном. Приведённый пример показывает одну строку HTML, но эта HTML-строка принадлежит более крупному компоненту:
src/app/click-me.component.ts
@Component({
selector: 'click-me',
template: `
<button (click)="onClickMe()">Click me!</button>
{{clickMessage}}`
})
export class ClickMeComponent {
clickMessage = '';
onClickMe() {
this.clickMessage = 'You are my hero!';
}
}
При нажатии пользователем на кнопку Angular вызывает метод onClickMe из ClickMeComponent.
Получение ввода пользователя из объекта $event
События DOM содержат полезную информацию, которая может пригодиться компоненту. В этом разделе показано, как привязаться к событию keyup текстового поля, чтобы получать ввод пользователя после каждого нажатия клавиши.
Следующий код прослушивает событие keyup и передаёт весь объём данных события ($event) обработчику события компонента.
src/app/keyup.components.ts (шаблон v.1)
template: `
<input (keyup)="onKey($event)">
<p>{{values}}</p>
`
При нажатии и отпускании пользователем клавиши происходит событие keyup, и Angular предоставляет соответствующий объект события DOM в переменной $event, которую этот код передаёт в качестве параметра методу компонента onKey().
src/app/keyup.components.ts (класс v.1)
export class KeyUpComponent_v1 {
values = '';
onKey(event: any) { // without type info
this.values += event.target.value + ' | ';
}
}
Свойства объекта $event зависят от типа события DOM. Например, событие мыши содержит другую информацию, чем событие редактирования текстового поля.
Все стандартные объекты событий DOM имеют свойство target, ссылку на элемент, который вызвал событие. В данном случае, target ссылается на элемент <input>, а event.target.value возвращает текущее содержимое этого элемента.
После каждого вызова метод onKey() добавляет содержимое значения текстового поля в список в свойстве компонента values, за которым следует разделитель (|). Интерполяция отображает накапливаемые изменения в значении текстового поля из свойства values.
Предположим, пользователь вводит буквы "abc", а затем удаляет их по одной с помощью клавиши Backspace. Вот что отображается на пользовательском интерфейсе:
a | ab | abc | ab | a | |
В качестве альтернативы вы можете накапливать отдельные клавиши, заменив
event.keyнаevent.target.value, в этом случае тот же ввод пользователя произведёт:a | b | c | backspace | backspace | backspace |
Ввод $event
В приведённом выше примере объект $event приводится к типу any. Это упрощает код, но сопряжено с потерей информации. Нет информации о типах, которая могла бы раскрыть свойства объекта события и предотвратить досадные ошибки.
Следующий пример переписывает метод с использованием типов:
src/app/keyup.components.ts (класс v.1 - с типами)
export class KeyUpComponent_v1 {
values = '';
onKey(event: KeyboardEvent) { // with type info
this.values += (<HTMLInputElement>event.target).value + ' | ';
}
}
Переменная $event теперь является конкретным KeyboardEvent. Не все элементы имеют свойство value, поэтому происходит приведение target к элементу типа input. Метод OnKey более чётко выражает то, что он ожидает от шаблона и как он интерпретирует событие.
Использование $event — сомнительная практика
Тип объекта события раскрывает существенный недостаток передачи всего объекта DOM события в метод: компонент слишком сильно зависит от деталей реализации шаблона. Он не может извлечь информацию без знания большего, чем ему следует о реализации HTML. Это нарушает разделение обязанностей между шаблоном (то, что видит пользователь) и компонентом (как приложение обрабатывает данные пользователя).
Следующий раздел демонстрирует, как использовать переменные ссылки на шаблон для решения этой проблемы.
Получение ввода пользователя с помощью переменной ссылки на шаблон
Есть другой способ получить данные пользователя: использовать переменные ссылки на шаблон Angular. Эти переменные предоставляют прямой доступ к элементу изнутри шаблона. Чтобы объявить переменную ссылки на шаблон, поместите перед идентификатором символ решётки (#).
Следующий пример использует переменную ссылки на шаблон для реализации обратной связи по нажатию клавиши в простом шаблоне.
src/app/loop-back.component.ts
@Component({
selector: 'loop-back',
template: `
<input #box (keyup)="0">
<p>{{box.value}}</p>
`
})
export class LoopbackComponent { }
Переменная ссылки на шаблон с именем box, объявленная для элемента <input>, ссылается на сам элемент <input>. Код использует переменную box для получения значения value элемента input и отображает его с помощью интерполяции между тегами <p>.
Шаблон полностью автономный. Он не привязан к компоненту, и компонент ничего не делает.
Введите что-нибудь в текстовое поле и наблюдайте, как отображение обновляется при каждом нажатии клавиши.
Это не будет работать, если вы не привяжетесь к событию.
Angular обновляет привязки (и, следовательно, экран) только в том случае, если приложение что-то делает в ответ на асинхронные события, такие как нажатие клавиши. В этом примере код привязывает событие
keyupк числу 0 — наименьшему возможному выражению шаблона. Хотя выражение ничего полезного не делает, оно удовлетворяет требованию Angular, чтобы Angular обновлял экран.
Получить доступ к текстовому полю с помощью переменной ссылки на шаблон проще, чем через объект $event. Вот переработка предыдущего примера keyup с использованием переменной ссылки на шаблон для получения ввода пользователя.
src/app/keyup.components.ts (v2)
@Component({
selector: 'key-up2',
template: `
<input #box (keyup)="onKey(box.value)">
<p>{{values}}</p>
`
})
export class KeyUpComponent_v2 {
values = '';
onKey(value: string) {
this.values += value + ' | ';
}
}
Приятный аспект этого подхода заключается в том, что компонент получает чистые значения данных из представления. Он больше не требует знания о $event и его структуре.
Фильтрация событий клавиш (с key.enter)
Обработчик события (keyup) получает каждое нажатие клавиши. Иногда важна только клавиша Enter, так как она сигнализирует о завершении ввода. Один из способов уменьшить шум — проверить каждое нажатие $event.keyCode и выполнить действие только при нажатии Enter.
Есть более простой способ: привяжитесь к псевдособытию Angular keyup.enter. Тогда Angular вызовет обработчик событий только при нажатии пользователем клавиши Enter.
src/app/keyup.components.ts (v3)
@Component({
selector: 'key-up3',
template: `
<input #box (keyup.enter)="onEnter(box.value)">
<p>{{value}}</p>
`
})
export class KeyUpComponent_v3 {
value = '';
onEnter(value: string) { this.value = value; }
}
Вот как это работает.
При потере фокуса
В предыдущем примере текущее состояние текстового поля теряется, если пользователь переводит фокус, кликая в другой части страницы, не нажав Enter. Свойство компонента value обновляется только при нажатии Enter.
Чтобы исправить эту проблему, прослушайте и событие нажатия клавиши Enter, и событие потери фокуса.
src/app/keyup.components.ts (v4)
@Component({
selector: 'key-up4',
template: `
<input #box
(keyup.enter)="update(box.value)"
(blur)="update(box.value)">
<p>{{value}}</p>
`
})
export class KeyUpComponent_v4 {
value = '';
update(value: string) { this.value = value; }
}
Объединение всего
На предыдущей странице показано, как отображать данные. На этой странице были продемонстрированы методы привязки событий.
Теперь объединим всё это в микро-приложение, которое может отображать список героев и добавлять новых героев в этот список. Пользователь может добавить героя, введя имя героя в текстовое поле и нажав кнопку Добавить.
Ниже представлен компонент «Небольшой тур по героям».
src/app/little-tour.component.ts
@Component({
selector: 'little-tour',
template: `
<input #newHero
(keyup.enter)="addHero(newHero.value)"
(blur)="addHero(newHero.value); newHero.value='' ">
<button (click)="addHero(newHero.value)">Add</button>
<ul><li *ngFor="let hero of heroes">{{hero}}</li></ul>
`
})
export class LittleTourComponent {
heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
addHero(newHero: string) {
if (newHero) {
this.heroes.push(newHero);
}
}
}
Наблюдения
-
Используйте переменные шаблона для ссылки на элементы — Переменная шаблона
newHeroссылается на элемент<input>. Вы можете ссылаться наnewHeroиз любого элемента-сестры или дочернего элемента<input>элемента. -
Передавайте значения, а не элементы — Вместо того, чтобы передавать
newHeroв метод компонентаaddHero, получите значение текстового поля и передайте это вaddHero. -
Сохраняйте выражения шаблона простыми — Событие
(blur)привязано к двум выражениям JavaScript. Первое выражение вызываетaddHero. Второе выражение,newHero.value='', очищает текстовое поле после добавления нового героя в список.
Исходный код
Ниже представлен весь код, обсуждаемый на этой странице.
import { Component } from '@angular/core';
@Component({
selector: 'click-me',
template: `
<button (click)="onClickMe()">Click me!</button>
{{clickMessage}}`
})
export class ClickMeComponent {
clickMessage = '';
onClickMe() {
this.clickMessage = 'You are my hero!';
}
}
import { Component } from '@angular/core';
@Component({
selector: 'key-up1',
template: `
<input (keyup)="onKey($event)">
<p>{{values}}</p>
`
})
export class KeyUpComponent_v1 {
values = '';
/*
onKey(event: any) { // without type info
this.values += event.target.value + ' | ';
}
*/
onKey(event: KeyboardEvent) { // with type info
this.values += (<HTMLInputElement>event.target).value + ' | ';
}
}
//////////////////////////////////////////
@Component({
selector: 'key-up2',
template: `
<input #box (keyup)="onKey(box.value)">
<p>{{values}}</p>
`
})
export class KeyUpComponent_v2 {
values = '';
onKey(value: string) {
this.values += value + ' | ';
}
}
//////////////////////////////////////////
@Component({
selector: 'key-up3',
template: `
<input #box (keyup.enter)="onEnter(box.value)">
<p>{{value}}</p>
`
})
export class KeyUpComponent_v3 {
value = '';
onEnter(value: string) { this.value = value; }
}
//////////////////////////////////////////
@Component({
selector: 'key-up4',
template: `
<input #box
(keyup.enter)="update(box.value)"
(blur)="update(box.value)">
<p>{{value}}</p>
`
})
export class KeyUpComponent_v4 {
value = '';
update(value: string) { this.value = value; }
}
import { Component } from '@angular/core';
@Component({
selector: 'loop-back',
template: `
<input #box (keyup)="0">
<p>{{box.value}}</p>
`
})
export class LoopbackComponent { }
import { Component } from '@angular/core';
@Component({
selector: 'little-tour',
template: `
<input #newHero
(keyup.enter)="addHero(newHero.value)"
(blur)="addHero(newHero.value); newHero.value='' ">
<button (click)="addHero(newHero.value)">Add</button>
<ul><li *ngFor="let hero of heroes">{{hero}}</li></ul>
`
})
export class LittleTourComponent {
heroes = ['Windstorm', 'Bombasto', 'Magneta', 'Tornado'];
addHero(newHero: string) {
if (newHero) {
this.heroes.push(newHero);
}
}
}
Заключение
Вы освоили базовые инструменты для реагирования на ввод пользователя и жесты.
Эти методы удобны для демонстраций небольших масштабов, но при обработке большого объёма ввода пользователя быстро становятся громоздкими и неудобными. Двунаправленная привязка данных — более элегантный и компактный способ перемещения значений между полями ввода и свойствами модели. На следующей странице, Forms, объясняется, как создавать двунаправленные привязки с NgModel.
Следующий шаг
Формы
© 2010–2017 Google, Inc.
Licensed under the Creative Commons Attribution License 4.0.
https://v2.angular.io/docs/ts/latest/guide/user-input.html