Search code examples
htmlangulareventsautocompleteangular-material

How to make tab key as enter key in Angular Material?


this is my angular material auto complete code

<input type="search" id="setId" name="setId" [attr.list]='collectionType' [(ngModel)]="selValue" class="text-box"
  placeholder="--Select--" (focus)="ValidateParent()" (keyup.tab)="test()" (keyup)="EmitValues($event)" [id]="setId"
  [matAutocomplete]="auto" [title]="selValue" [placeholder]='WaterMarkText'>


<div [hidden]="IsCascading">
  <mat-autocomplete [id]="collectionType" #auto="matAutocomplete" (optionSelected)='onChange($event)'>
    <mat-option *ngFor="let items of codeList" [value]="items.text" [attr.data-text]='items.text' [id]="items.value">
      {{items.text}}
    </mat-option>
  </mat-autocomplete>
</div>

Angular material had a problem with tab selection.like the material auto complete not able to select the value while click the tab button. but it's working while click the enter button. So manually I need to overwrite the enter key event on tab key event. How could possible?


Solution

  • Improve my comment, and based on the response we can create a directive

    import {
        Directive,
        AfterViewInit,
        OnDestroy,
        Optional
    } from '@angular/core';
    import {
        MatAutocompleteTrigger
    } from '@angular/material';
    
    
    @Directive({
        selector: '[tab-directive]'
    })
    export class TabDirective implements AfterViewInit, OnDestroy {
        observable: any;
        constructor(@Optional() private autoTrigger: MatAutocompleteTrigger) {}
        ngAfterViewInit() {
            this.observable = this.autoTrigger.panelClosingActions.subscribe(x => {
                if (this.autoTrigger.activeOption) {
                    this.autoTrigger.writeValue(this.autoTrigger.activeOption.value)
                }
            })
        }
        ngOnDestroy() {
            this.observable.unsubscribe();
        }
    }
    

    You use:

    <input tab-directive type="text" matInput [formControl]="myControl" 
          [matAutocomplete]="auto" >
    

    (see stackblitz)

    Update We can control only tab.key, else always you close, you get the selected value, so

    @Directive({
        selector: '[tab-directive]'
    })
    export class TabDirective {
        observable: any;
        constructor(@Optional() private autoTrigger: MatAutocompleteTrigger) {}
    
        @HostListener('keydown.tab', ['$event.target']) onBlur() {
            if (this.autoTrigger.activeOption) {
                this.autoTrigger.writeValue(this.autoTrigger.activeOption.value)
            }
        }
    
    }
    

    (see a new stackblitz)

    Update 2 I don't believe this answer has so many upvotes because it's wrong. As @Andrew allen comments, the directive not update the control. Well, It's late, but I try to solve. One Option is use

    this.autoTrigger._onChange(this.autoTrigger.activeOption.value)
    

    Anohter idea is inject the ngControl, so

    constructor(@Optional() private autoTrigger: MatAutocompleteTrigger,
        @Optional() private control: NgControl) {}
    ngAfterViewInit() {
        this.observable = this.autoTrigger.panelClosingActions.subscribe(x => {
            if (this.autoTrigger.activeOption) {
                const value = this.autoTrigger.activeOption.value;
                if (this.control)
                    this.control.control.setValue(value, {
                        emit: false
                    });
                this.autoTrigger.writeValue(value);
            }
        })
    }