Search code examples
angulartypescriptsettimeout

angular ngAfterViewInit element focus not workin


When loading a component, I want you to focus on the first element after initialization. I found a tutorial for this, but it doesn't want to work for me.

https://davidmcintosh.medium.com/auto-focusing-an-angular-input-the-easy-way-part-1-dcb1799e025f

But if I put it in a timer that is 0 then it works great. But I don't want to use timer.

ngAfterViewInit(): void {
    timer(0).subscribe(() => this.firstElement.nativeElement.focus());
}

Why do I need a timer with such a ridiculous value?

Here is my HTML code:

<p class="news-title" tabindex="0" #firstElement>{{ 'news.title' | translate }}</p>
<ul class="news-list" role="list">
    <li role="listitem" tabindex="0" class="list-item">{{ 'news.item-1' | translate }}</li>
    <li role="listitem" tabindex="0" class="list-item">{{ 'news.item-2' | translate }}</li>
    <li role="listitem" tabindex="0" class="list-item">{{ 'news.item-3' | translate }}</li>
</ul>

Solution

  • It is working for me, since your <p> tag is static which would always be there, you can query viewChild with {static: true}, that case it would query the element before change detaction, see stackblitz.

      @ViewChild('firstElement', {read: ElementRef, static: true})
      firstElement?: ElementRef<unknown>;
    
      ngAfterViewInit(): void {
        (this.firstElement?.nativeElement as any).focus();
      }
    

    Better solution would be use material's A11y CDK cdkTrapFocusAutoCapture, see stackblitz

    <p cdkTrapFocus="false" cdkTrapFocusAutoCapture class="news-title" tabindex="0" #firstElement>{{ 'news.title' }}</p>
    <ul class="news-list" role="list">
      <li role="listitem" tabindex="0" class="list-item">{{ 'news.item-1' }}</li>
      <li role="listitem" tabindex="0" class="list-item">{{ 'news.item-2' }}</li>
      <li role="listitem" tabindex="0" class="list-item">{{ 'news.item-3' }}</li>
    </ul>
    

    Note:

    • Focus can only focus on focusable element
    • Be aware whether it's your translate pipe introducing timing issue, if you are using transloco may be try to use transloco structure directive instead of pipe.