当达到最大长度时,将输入焦点移至下一个输入框 - Angular 4 / Typescript

12

当用户在第一个输入字段中输入了最大长度的字符时,我希望能将焦点从该输入字段移至另一个输入字段。因此,在下面的示例中,当用户输入2个字符到"day"输入框中,焦点会自动切换到"month"输入框。

目前我的代码如下:

<input formControlName="day" maxlength="2" placeholder="DD" type="text" (keyup)="keytab($event)" />
<input formControlName="month" maxlength="2" placeholder="MM" type="text" (keyup)="keytab($event)" />
<input formControlName="year" maxlength="4" placeholder="YYYY" type="text" />

而在我的TS文件中:

 keytab(event){
    let nextInput = event.srcElement.nextElementSibling; // get the sibling element

    var target = event.target || event.srcElement;
    var id = target.id
    console.log(id.maxlength); // prints undefined

    if(nextInput == null)  // check the maxLength from here
        return;
    else
        nextInput.focus();   // focus if not null
}

我知道我的TS文件中的代码是错误的,但我一直在尝试找到一种获取maxLength属性并移动焦点的方法。现在只要输入框中有keyup事件,焦点就会移动。

请问有人能告诉我如何从keytab函数中访问输入框的maxLength属性吗?谢谢。

我正在使用Angular 4

编辑 - 我正在尝试获取maxLength值,然后将其与输入值长度进行比较。如果输入值更多,则将焦点移到输入框。


2
可能是重复的问题,参考如何将焦点设置到另一个输入框? - Jeremy Thille
不是这样的 - 我说过我已经解决了焦点转移的部分 - 我不知道如何访问maxLength。但感谢提供链接。那里有有趣的信息。 - Jose the hose
只需使用 <input type="date"> - Endless
你为什么使用文本输入类型而不是数字? - Naga
5个回答

8
这里是一个通用的(指令)解决方案,当达到最大长度时移动到下一个相似的控件类型。
1- 创建指令。
import { Directive, HostListener } from '@angular/core';

@Directive({
  selector: 'input[moveNextByMaxLength], textarea[moveNextByMaxLength]',
})
export class MoveNextByMaxLengthDirective {
  @HostListener('keyup', ['$event']) onKeyDown(keyboardEvent: KeyboardEvent) {
    const target = keyboardEvent.target as
      | HTMLInputElement
      | HTMLTextAreaElement
      | null;

    if (!target || target.maxLength !== target.value.length) return;

    keyboardEvent.preventDefault();

    const { type } = target;
    let { nextElementSibling } = target;

    while (nextElementSibling) {
      if (
        (nextElementSibling as HTMLInputElement | HTMLTextAreaElement).type ===
        type
      ) {
        (nextElementSibling as HTMLInputElement | HTMLTextAreaElement).focus();
        return;
      }

      nextElementSibling = nextElementSibling.nextElementSibling;
    }
  }
}

2- 在模块中声明指令

@NgModule({
  imports: [ BrowserModule ],
  declarations: [
    AppComponent,
    MoveNextByMaxLengthDirective 
  ],
  bootstrap: [ AppComponent ]
})

3- 在组件中使用指令

<input formControlName="day" maxlength="2" moveNextByMaxLength placeholder="DD" type="text" (keyup)="keytab($event)" />
<input formControlName="month" maxlength="2" moveNextByMaxLength placeholder="MM" type="text" (keyup)="keytab($event)" />
<input formControlName="year" maxlength="4" placeholder="YYYY" type="text" />

它的工作很好,但问题在于如果你想通过退格键删除数据...它不会回到先前的输入....我正在为4个OTP输入框使用这个解决方案。 - Shashwat Gupta
使用div时它无法工作,需要做哪些更改。<div><input formControlName="day" maxlength="2" moveNextByMaxLength placeholder="DD" type="text" (keyup)="keytab($event)" /> </div> <div><input formControlName="month" maxlength="2" moveNextByMaxLength placeholder="MM" type="text" (keyup)="keytab($event)" /> </div> <div><input formControlName="year" maxlength="4" placeholder="YYYY" type="text" /> </div> - pushp

4
使用不同的方法。Angular不像jQuery那样从现有DOM中选择元素并读取属性,因为Angular是从数据生成DOM的。因此,如果可能的话,读取输入的maxlength属性会很困难,而且无论如何都会很笨拙和“非Angular风格”。
相反,使用不同的方法,在keyup函数中传递maxLength:
<input type="text" (keyup)="keytab($event, 2)" />
<input type="text" (keyup)="keytab($event, 4)" />


keytab(event, maxLength){
   console.log(maxlength); // 2 or 4
   // .......
}

谢谢你的回答。我现在将额外的参数传递给keytab函数,然后从那里获取输入值的长度并进行比较 - 如果(event.target.value.length < maxLength)... - Jose the hose
@Josethehose,您能否请注释完整的逻辑呢?谢谢。 - Md Alamin

3
另一个适用于Angular 9+的简单答案。
<input #input1 (keyup)="(input1.value.length == 2) ? input2.focus() : ''" type="text" maxlength="2">
<input #input2 (keyup)="(input2.value.length == 2) ? input3.focus() : ''" type="text" maxlength="2">
<input #input3 (keyup)="(input2.value.length == 2) ? submit.focus() : ''"  type="text" maxlength="2">

<button #submit type="submit">Submit</button>

2

如果您正在使用响应式表单,可以考虑以下方式:

import { FormGroup, FormBuilder, Validators } from "@angular/forms";
import { Component, OnInit, ViewChild, ElementRef } from "@angular/core";
import { filter } "rxjs/operators";

@Component({
  selector: "app-form",
  template: `
    <form [formGroup]="form">
        <input formControlName="day" placeholder="DD" type="text" #day />
        <input formControlName="month" placeholder="MM" type="text" #month />
        <input formControlName="year" placeholder="YYYY" type="text" #year />
    </form>
`
})
export class FormComponent implements OnInit {
  form: FormGroup;

  @ViewChild("day") dayElement: ElementRef;

  @ViewChild("month") monthElement: ElementRef;

  @ViewChild("year") yearElement: ElementRef;

  constructor(private fb: FormBuilder) {}

  ngOnInit() {
    const dayMaxLength = 2;
    const monthMaxLength = 2;
    const yearMaxLength = 4;

    this.form = this.fb.group({
      day: ["", [Validators.required, Validators.maxLength(dayMaxLength)]],
      month: ["", [Validators.required, Validators.maxLength(monthMaxLength)]],
      year: ["", [Validators.required, Validators.maxLength(yearMaxLength)]]
    });

    this.form.get("day").valueChanges
      .pipe(filter((value: string) => value.length === dayMaxLength))
      .subscribe(() => this.monthElement.nativeElement.focus());

    this.form.get("month").valueChanges
      .pipe(filter((value: string) => value.length === monthMaxLength))
      .subscribe(() => this.yearElement.nativeElement.focus());
}

基本上,订阅日和月表单控件的值更改,过滤每个流,以使其仅在值等于最大长度时继续,然后将焦点设置到下一个元素。可能值得注意的是,这些也需要取消订阅。


这看起来很有趣。我稍后会试一下并告诉你。非常感谢! - Jose the hose
1
我已经尝试了这个解决方案。this.form.controls['day'].valueChanges 能够正常工作,而不是 this.form.get("day").valueChanges - Emon
这绝对是在Angular中做事情最优雅的方式。 就像@EmonZan所说,你的例子在使用get时不起作用。 最好的方法可能是this.form.controls.day.valueChanges - Wirde

1

纯 JavaScript 方法

let allInputs = document.getElementsByTagName('input');
let index = 0;
for(i=0;i<allInputs.length;i++) {
allInputs[i].onkeydown =trackInputandChangeFocus;
}

function trackInputandChangeFocus() {
let allInputsArr = Array.from(allInputs); 
let presentInput = allInputsArr.indexOf(this)
if(this.value.length == parseInt(this.getAttribute('maxlength'))) {
      let next;
      if(presentInput != 2) next = allInputsArr[presentInput+1]
      else next = allInputsArr[0]
      next.focus();
    }
}
<input formControlName="day" maxlength="2" placeholder="DD" type="text" (keyup)="keytab($event)" />
<input formControlName="month" maxlength="2" placeholder="MM" type="text" (keyup)="keytab($event)" />
<input formControlName="year" maxlength="4" placeholder="YYYY" type="text" />


2
但是有什么意义呢?OP明确表示他们使用的是Angular 4。 - Jeremy Thille

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接