Search code examples
angularangular-directive

Angular Custom Directive Set Tab Index On Enter Key Press


I would like to fire the Tab key event on keydown.Enter in a the whole form. For which with the following code, I am running the functions on the parent Div. The event is detected in the console but no changes happens on the input (I mean the focus does not move from the input as it moves by the Tab key).

TEMPLATE: <Div #parentnode (keydown)="KeyEventEmitter($event, parentnode)>

TS FILE:

KeyEventEmitter(event:KeyboardEvent, el) {
//event.preventDefault;
let keyEvent = new KeyboardEvent("keyDown", 
{key : "Tab", 
bubbles: true, 
code: "Tab", 
location: 0, 
composed: true,
cancelable: true,
ctrlKey: false,
altKey: false,
detail: 0,
shiftKey: false
});
console.log('I am custom keyevent', keyEvent)
el.dispatchEvent(keyEvent);
}

}

Will appreciate any help. Thanks


Solution

  • You can create a tabIndex directive and inside that directive set focus of next indexed element on enter key press.

    tab.directive.ts

    import { Directive, Input, ElementRef, HostListener, OnInit } from'@angular/core';
    import { TabService } from './tab.service';
    import { BehaviorSubject } from 'rxjs';
    
    @Directive({
     selector: '[tabIndex]'
    })
    export class TabDirective implements OnInit {
     private _index: number;
    
     get index() {
       return this._index;
     }
     @Input('tabIndex')
     set index(i: any) {
       this._index = parseInt(i);
     }
    
    @HostListener('keydown', ['$event'])
    onInput(e: any) {
     if (e.which === 13) {
      e.preventDefault();
      console.log('index', this.index+1)
      this.tabService.selectedInput.next(this.index + 1);
     }
    }
    constructor(private el: ElementRef, private tabService: TabService) {}
    
    ngOnInit(){
      this.tabService.selectedInput.subscribe((i) => {
        if (i === this.index) {
          this.el.nativeElement.focus()
         }
       });
      }
    }
    

    Create a tab service where to trigger next index using BehaviourSubject on each key down press.

    tab.service.ts

    import { Injectable } from '@angular/core';
    import { BehaviorSubject } from 'rxjs';
    
    @Injectable({providedIn: 'root'})
    export class TabService {
     selectedInput: BehaviorSubject<number> = new BehaviorSubject<number>(1);
    }
    

    Now in template assign tabIndex to each element sequentially.

    <input type="text" tabIndex="1">
    <input type="text" tabIndex="2">
    <input type="text" tabIndex="3">
    <a href="https://google.com" tabIndex="4">Google</a>
    

    You can find complet working example DEMO on stackblitz