#angular #ionic-framework #ionic4
#angular #ionic-framework #ionic4
Вопрос:
Я пытаюсь создать ионный (угловой) компонент для ввода вывода. Это будет 4 ion-input
(по одному на каждое число), которые принимают только один символ и которые при включении ionInput
(при нажатии клавиши клавиатуры) проверяют ввод и принимают (если это так [0-9]
) или отклоняют его. Если ввод принят, затем установите фокус на следующее поле; если он отклонен, затем удалите его и продолжайте фокусироваться на текущем поле. Ну, я не знаю почему, но мне это не удается. Поведение ion-input
s не соответствует ожиданиям. В моем коде происходит то, что ввод отражается на следующем поле, а фокус устанавливается на поле после следующего. Например, я набираю a 1
в поле 0, затем я получаю a 1
в поле 0, другое 1
в поле 1 и фокус на поле 2
; затем я набираю a 9
в поле 2 и получаю a 9
в 2, другое в 3 и фокус на 1
.
Кто-нибудь знает, что происходит? И, самое главное, как это решить? Мой код следующий:
<ion-input *ngFor="let digit of digits; index as i"
[id]="'digitField' i"
[(ngModel)]="digit"
inputmode="decimal"
(ionInput)="onFieldInput($event, i)"></ion-input>
public ngAfterViewInit(): void {
this.digitFields = [];
for (let i = 0; i < this.digits.length; i ) {
this.digitFields[i] = document.getElementById('digitField' i) as HTMLIonInputElement;
}
}
public onFieldInput($event, fieldIndex: number) {
const newInput = $event.detail.data;
const nextIndex = (fieldIndex 1) % this.digits.length;
const currentElement = this.digitFields[fieldIndex];
let nextElement = this.digitFields[nextIndex];
if (!/d/.test(newInput)) {
this.digits[fieldIndex] = '';
currentElement.setFocus();
} else {
this.digits[fieldIndex] = newInput;
nextElement.setFocus();
}
}
Ответ №1:
Ну, я нашел способ сделать это.
Прежде чем читать код (который работает сейчас), я хочу кое-что прокомментировать: возможно, есть более простой способ, основанный на коде вопроса, поскольку в какой-то момент я понял, что использование digits
массива в html-коде вызывает проблемы, даже когда я использую его только для *ngFor
инициализации. Кроме того, preventDefault()
stopImmediatePropagation()
в какой-то момент помогло использование и.
В любом случае, когда мой код начал работать, я уже давно отказался от ionInput
event, поэтому я использую keyDown
вместо этого. Также keyDown
дает мне возможность прослушать backspace.
Итак, нет более длинного введения, вот рабочий фрагмент:
<div class="pin-input-container" #fieldsContainer>
<ion-input *ngFor="let n of dummyArray; index as i"
type="text"
inputmode="numeric"
[type]="hideInput ? 'password' : 'text'"
(keydown)="onKeyDown($event, i)"></ion-input>
</div>
export class PinInputComponent {
private static readonly TAG = 'PinInputComponent';
@ViewChild('fieldsContainer') fieldsContainer;
@Input() numberOfDigits = 4;
@Input() hideInput = false;
@Output() completed = new EventEmitter<string[]>();
@Output() partial = new EventEmitter<string[]>();
private digits: string[];
public dummyArray: void[];
public constructor() {
this.dummyArray = new Array(this.numberOfDigits);
this.digits = new Array(this.numberOfDigits);
}
public onKeyDown($event: KeyboardEvent, fieldIndex: number): void {
$event.preventDefault();
$event.stopImmediatePropagation();
const domElement = $event.srcElement.parentElement as HTMLIonInputElement;
if (/d/.test($event.key)) {
// Number: set field content, set digit in current position and go to next field
domElement.value = $event.key;
this.digits[fieldIndex] = $event.key;
const nextField = domElement.nextElementSibling as HTMLIonInputElement;
if (nextField) nextField.setFocus().then();
} else if ($event.key === 'Backspace') {
// Delete: clear content in field and this.digits and go to previous field
domElement.value = null;
this.digits[fieldIndex] = null;
const previousField = domElement.previousElementSibling as HTMLIonInputElement;
if (previousField) previousField.setFocus().then();
} else {
// Illegal key: clear field and stay there
setTimeout(() => domElement.value = null, 10);
}
this.partial.emit(this.digits);
// If the input was last digit and all digits are set, then emit completed
if (fieldIndex >= this.digits.length - 1) {
for (const digit of this.digits) {
if (digit === null) {
return;
}
}
this.completed.emit(this.digits);
}
}
public setFocus(): void {
(this.fieldsContainer.nativeElement.childNodes[1] as HTMLIonInputElement).setFocus().then();
}
}
Обратите внимание, что я использую setTimeout
недопустимый символ if. Я не знаю причину, но без нее это не сработает. Я предполагаю, что какой-то процесс работает в фоновом режиме в ionic и нарушает фокусировку и распространение значений. Я пробовал еще меньшее количество времени и все еще работает (оставил его на 10 мс для безопасности), но без него не будет работать.