I have an Angular 2+ form group and each form field has tabIndex.
How do I change focus to the next form field on each Enter key press (similar to pressing tab)?
JavaScript Reference - Enter key press behaves like a Tab in Javascript
I have an Angular 2+ form group and each form field has tabIndex.
How do I change focus to the next form field on each Enter key press (similar to pressing tab)?
JavaScript Reference - Enter key press behaves like a Tab in Javascript
I would do this with a simple directive and a much simpler service.
tab.directive.ts
import { Directive, Input, ElementRef, HostListener, OnInit } from '@angular/core';
import { TabService } from './tab.service';
type IKNOWISNUMBER = any;
type IKNOWISSTRING = any;
@Directive({
selector: '[tabIndex]'
})
export class TabDirective implements OnInit {
private _index: number;
get index(): IKNOWISNUMBER{
return this._index;
}
@Input('tabIndex')
set index(i: IKNOWISSTRING){
this._index = parseInt(i);
}
@HostListener('keydown', ['$event'])
onInput(e: any) {
if (e.which === 13) {
this.tabService.selectedInput.next(this.index + 1)
e.preventDefault();
}
}
constructor(private el: ElementRef, private tabService: TabService) {
}
ngOnInit(){
this.tabService.selectedInput.subscribe((i) => {
if (i === this.index){
this.el.nativeElement.focus();
}
});
}
}
tab.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable()
export class TabService {
selectedInput: BehaviorSubject<number> = new BehaviorSubject<number>(1);
}
I've created a little stackblitz to show how it works.
P.S. Remember to provide the tab.service inside every component with a form, cause you need a specific instance for each form.
Here's a very simple approach, with just a few lines of code (which I also posted here:Change behavior of Enter key . . . ):
First, in your Template
when you dynamically create your Input
elements: 1. populate the tabIndex
attribute with a unique number, 2. populate a super-simple custom "Tag" Directive with the same unique number as the tabIndex
, and 3. set up a Keydown "Enter" event listener:
Template:
<ng-container *ngFor="let row in data">
<input tabindex ="{{row[tabCol]}}" [appTag]="{{row[tabCol]}}" (keydown.enter)="onEnter($event)" . . . />
</ng-container>
In your component
, your super-simple event-listener onEnter()
:
@ViewChildren(TagDirective) ipt!: QueryList<ElementRef>;
onEnter(e: Event) {
this.ipt["_results"][(<HTMLInputElement>e.target).tabIndex%(+this.ipt["_results"].length-1)+1].el.nativeElement.focus();
}
Note: The modulus (%) operation is just to make sure that if you're at the last Input
, you'll get cycled back to the first input.
Super-simple, bare-minimum "Tag" Directive
import { Directive, ElementRef, Input } from '@angular/core';
@Directive({
selector: '[appTag]'
})
export class TagDirective {
@Input('appTag') id: number;
constructor(public el: ElementRef) { }
}
There's probably even a way to get rid of the "Tag" `Directive altogether and make it even more simple, but I haven't had time to figure out how to do that yet . . .
export class InputNumberComponent implements OnInit {
@Input() model: number;
@Input() tabIndex: number ;
@Output()
changedValue = new EventEmitter<number>();
constructor() { }
valueChanged(value): void {
this.changedValue.emit(value);
}
}
<input tabindex="{{tabIndex}}" [(ngModel)]="model" (change)="valueChanged(model)"/>
if use angular and make input component only use html "tabindex" in html
and define @input to .ts file get tabindex @Input() tabIndex: number ;