5

I'm using ng-select and have a custom filter header template defined which contains an input.

I would like the input to receive focus when the dropdown is opened for the select, but I cant figure out how to.

I have an example here -> https://stackblitz.com/edit/angular-playground-f57jog

I did try attaching to the ng-select (open) output and calling focus() on my input element, but this fails for me.

Whats the correct approach here? Thanks

mindparse
  • 6,115
  • 27
  • 90
  • 191

6 Answers6

6

I would create special directive and reuse it wherever I need it:

@Directive({
  selector: '[appAutofocus]'
})
export class AutofocusDirective implements OnInit {

  constructor(private el: ElementRef) {
  }

  ngOnInit() {
    this.el.nativeElement.focus();
  }
}

html

<input appAutofocus ... />

So it should work in Chrome, Firefox, etc..

Forked Stackblitz

yurzui
  • 205,937
  • 32
  • 433
  • 399
4

You can use this method:

in your html:

<ng-select #api [items]="cars"
          [virtualScroll]="true"
          [loading]="loading"
          bindLabel="brand"
          bindValue="id"
          (scroll)="onScroll($event)"
          (scrollToEnd)="onScrollToEnd()"
          [dropdownPosition]="'bottom'"
          [searchable]="false"
          [(ngModel)]="selectedCar2"
          [searchFn]="customSearchFn"
          (change)="onChange($event)"
          (open)="focusInputField()">

note the (open) changed.

in your .ts file you add:

    @ViewChild('filterInput') filterInput:ElementRef;


    focusInputField() {
      setTimeout(() => {
      this.filterInput.nativeElement.focus()
      }, 10)
    }

This should work for both Chrome and Firefox.

Korfoo
  • 571
  • 2
  • 12
0

Just use ViewChildren and susbcribe to changes, then focus. That's.

@ViewChildren('filterInput') filterInput : QueryList<ElementRef>;

onOpen()
{
  this.filterInput.changes.subscribe(res=>{
      this.filterInput.first.nativeElement.focus()
  })
}

And in your .html

<ng-select ...  (open)="onOpen()"></ng-select>

See your forked stackblitz

Eliseo
  • 50,109
  • 4
  • 29
  • 67
0

There is a timing issue between when the ng-select open callback is fired and the filterInput element is actually rendered. Your syntax is right, but filterInput is undefined when ng-select open emits. Refer to the following error from debug console in your provided stackblitz:

ERROR TypeError: Cannot read property 'nativeElement' of undefined

One approach to resolving this issue is to delay calling focus on the undefined element within the open callback. Below I've done just that by 1) capturing the filterInput ElementRef via @ViewChild, 2) refactor your current focus logic into a method within the component and added 250 ms delay, and 3) calling said method using the ng-select component open event emitter. I've provided an RxJS alternative to step 2 as well if preferred.


app.component.ts

// 1
@ViewChild('filterInput') filterInput: ElementRef;

// 2
setFilterFocus() {
  setTimeout((() => { this.filterInput.nativeElement.focus() }).bind(this), 250)
}

app.component.html

<!-- 3 -->
<ng-select #api [items]="cars"
          [virtualScroll]="true"
          [loading]="loading"
          bindLabel="brand"
          bindValue="id"
          (scroll)="onScroll($event)"
          (scrollToEnd)="onScrollToEnd()"
          [dropdownPosition]="'bottom'"
          [searchable]="false"
          [(ngModel)]="selectedCar2"
          [searchFn]="customSearchFn"
          (change)="onChange($event)"
          (open)="setFilterFocus()">

Step 2 revisited - instead using RxJS

app.component.ts additional imports

import { of } from 'rxjs';
import { delay, tap } from 'rxjs/operators';

app.component.ts setFilterFocus RxJS style

setFilterFocus() {
    of(null)
      .pipe(
        delay(250), 
        tap(() => this.filterInput.nativeElement.focus()))
      .subscribe();
}
Matthew Thurston
  • 720
  • 5
  • 22
0
//component.html
<ng-select #select> </ng-select>
//component.ts
import { NgSelectComponent } from '@ng-select/ng-select';
// Inside the class
@ViewChild('select') select: NgSelectComponent; 

// AfterViewInit
 setTimeout(() => {
  this.select.focus();
 }, 100);
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Apr 14 '23 at 08:01
-1

Add the autofocus attribute to your input tag

Your code will be like this:

<input autofocus #filterInput style="width: 100%; line-height: 24px" type="text" (input)="api.filter($event.target.value)"/>

Updated version of your stackbliz demo here

Hope it helps :)

Community
  • 1
  • 1
asimhashmi
  • 4,258
  • 1
  • 14
  • 34