#javascript #angular
#javascript #angular
Вопрос:
У меня есть компонент с четырьмя полями ввода, которые могут принимать только числа. При вводе фокус переключается с текущего поля ввода на следующее. Удаление также работает (при нажатии обратного пробела) — удаление значения в текущем поле переместит фокус на предыдущее.
Проблема, с которой я сталкиваюсь, заключается в том, что текущая реализация довольно статична, что означает, что некоторые значения жестко закодированы. Если вы посмотрите на эту демонстрацию, вы увидите, что каждое (input)
событие отправляет жестко заданный индекс. То же самое с каждым (delete)
.
Другое ограничение заключается в том, что если я хочу добавить пятый ввод, мне нужно скопировать один из существующих входов и внести некоторые коррективы.
Итак, моя задача, которую я сейчас знаю, заключается в том, как сделать это более динамичным и гибким. Например, указание того, сколько должно быть входных данных. Также не кодируйте индексы жестко, но будьте в состоянии понять это из кода.
Есть предложения о том, как это сделать?
Ответ №1:
В этом примере я использую реактивную форму. Я бы сделал это отдельным компонентом, и вы бы просто передали количество цифр компоненту, который затем обрабатывает все остальное. Вероятно, вам нужно передать цифры родительскому компоненту, и для этого вы можете использовать @Output
. Вам не НУЖНО создавать компонент, но я бы сделал это ради чистоты 🙂
Итак, мы могли бы создать HelloComponent
(название, только что полученное из шаблона stackblitz), где мы создали бы форму, поместив в массив столько элементов управления формой, сколько вы указали:
@Input() numOfDigits;
@ViewChildren('inputs') inputs: QueryList<any>;
confirmCodeForm: FormGroup;
constructor(private fb: FormBuilder) {
this.confirmCodeForm = this.fb.group({
digits: this.fb.array([]) // create empty form initially
});
}
ngOnInit() {
// push form controls to the formarray
for (let i = 0; i< this.numOfDigits; i ) {
(this.confirmCodeForm.get('digits') as FormArray).push(this.fb.control(null))
}
}
Затем обработка событий и проверка правильности чисел, Изменение фокуса на поле и т.д., Которое запускается на keydown
:
check(index, field, event) {
if (isNaN(parseInt(event.key, 10)) amp;amp; event.key !== 'Backspace') {
event.preventDefault();
}
else if (field.value amp;amp; event.key !== 'Backspace') {
if (index < this.inputs.toArray().length - 1) {
this.inputs.toArray()[index 1].nativeElement.focus();
}
}
else if (event.key === 'Backspace') {
if (index > 0) {
field.setValue(null)
this.inputs.toArray()[index - 1].nativeElement.focus();
} else {
console.log('first field');
}
}
}
Затем в шаблоне мы бы повторили массив form, и все готово!
<form (ngSubmit)="confirmCode(confirmCodeForm.value)" [formGroup]="confirmCodeForm">
<div formArrayName="digits">
<input *ngFor="let field of confirmCodeForm.get('digits').controls;
let i = index"
#inputs
[maxLength]="1"
[formControlName]="i"
(keydown)="check(i, field, $event)">
</div>
</form>
Нет, этот компонент прост в использовании с помощью всего
<hello [numOfDigits]="4"></hello>
ДЕМОНСТРАЦИЯ
Комментарии:
1. Спасибо за ваши советы. Этот подход выглядит намного лучше, а также он более гибкий. Если я найду время, я постараюсь немного доработать его и выпустить как компонент с открытым исходным кодом.
2. @AT82 не могли бы вы подробнее рассказать о ситуации, когда нажат Backspace? При нажатии клавиши Backspace цифра из текущего ввода удаляется, а предыдущая — та, на которую перемещается фокус.
Ответ №2:
То, что вы ищете, — это *ngFor
директива. Смотрите: https://angular.io/guide/displaying-data#showing-an-array-property-with-ngfor
Я также разветвил ваш пример и изменил его: https://stackblitz.com/edit/angular-ug7b69?file=src/app/app.component.html
Однако при @HostListener
подходе s вы столкнетесь с другими проблемами, как вы вскоре заметите в примере. Я бы посоветовал изучить ngModel
директиву и / или угловые формы ( FormGroup
, FormControl
и т.д.) Для более безопасного способа обнаружения этих изменений ввода и реагирования на них.
Комментарии:
1. Спасибо за ваши предложения. Я уже пробовал
ngFor
, но результат был не таким хорошим. Проблема очевидна и в вашем форке. Может быть, это будет работать лучше, если я действительно изучуFormControl
.