Как использовать Angular4 для установки фокуса с помощью идентификатора элемента

Я новичок в Angular, и я пытаюсь использовать его, чтобы установить фокус на вход с идентификатором "input1". Я использую следующий код:

@ViewChild('input1') inputEl: ElementRef;

потом в компоненте:

 this.inputEl.nativeElement.focus();

Но это не работает. Что я делаю неправильно? Любая помощь будет высоко ценится.

Ответ 1

Один из ответов на вопрос, на который ссылается @Z.Bagley, дал мне ответ. Мне пришлось импортировать Renderer2 из @angular/core в мой компонент. Затем:

const element = this.renderer.selectRootElement('#input1');

// setTimeout(() => element.focus, 0);
setTimeout(() => element.focus(), 0);

Спасибо @MrBlaise за решение!

Ответ 2

составная часть

import { Component, ElementRef, ViewChild, AfterViewInit} from '@angular/core';
... 

@ViewChild('input1') inputEl:ElementRef;

ngAfterViewInit() {
      setTimeout(() => this.inputEl.nativeElement.focus());
}

HTML

<input type="text" #input1>

Ответ 3

Вот директива Angular4+, которую вы можете повторно использовать в любом компоненте. На основе кода, приведенного в ответе Ниль Т в этом вопросе.

import { NgZone, Renderer, Directive, Input } from '@angular/core';

@Directive({
    selector: '[focusDirective]'
})
export class FocusDirective {
    @Input() cssSelector: string

    constructor(
        private ngZone: NgZone,
        private renderer: Renderer
    ) { }

    ngOnInit() {
        console.log(this.cssSelector);
        this.ngZone.runOutsideAngular(() => {
            setTimeout(() => {
                this.renderer.selectRootElement(this.cssSelector).focus();
            }, 0);
        });
    }
}

Вы можете использовать его в шаблоне компонента следующим образом:

<input id="new-email" focusDirective cssSelector="#new-email"
  formControlName="email" placeholder="Email" type="email" email>

Дайте ввод id и передайте id в свойство cssSelector директивы. Или вы можете передать любой понравившийся вам cssSelector.

Комментарии от Niel T:

Поскольку единственное, что я делаю, - это сосредоточиться на элементе, мне не нужно заниматься детекцией изменений, поэтому я могу фактически запустить вызов renderer.selectRootElement вне Angular. Поскольку мне нужно предоставить время для рендеринга новых секций, секция элемента завершается в тайм-аут, чтобы разрешить время потоков рендеринга до того, как будет предпринята попытка выбора элемента. После того, как все это будет установлено, я могу просто вызвать элемент с помощью основных селекторов CSS.

Ответ 4

Это помогло мне (в ионной, но идея такая же) https://mhartington.io/post/setting-input-focus/

в шаблоне:

<ion-item>
      <ion-label>Home</ion-label>
      <ion-input #input type="text"></ion-input>
</ion-item>
<button (click)="focusInput(input)">Focus</button>

в контроллере:

  focusInput(input) {
    input.setFocus();
  }

Ответ 5

Вот директива, которую вы можете использовать в любом компоненте:

import { NgZone, Directive, ElementRef, AfterContentInit, Renderer2 } from '@angular/core';

@Directive({
    selector: '[appFocus]'
})
export class FocusDirective implements AfterContentInit {
    constructor(private el: ElementRef, private zone: NgZone, private renderer: Renderer2) {}

    ngAfterContentInit() {
        this.zone.runOutsideAngular(() => setTimeout(() => {
            this.renderer.selectRootElement(this.el.nativeElement).focus();
        }, 0));
    }
}

Использование:

<input type="text" appFocus>

Ответ 6

Я также сталкиваюсь с такой же проблемой после некоторого поиска, я нашел хорошее решение, поскольку @GreyBeardedGeek означало, что setTimeout является ключом этого решения. Он абсолютно прав. В вашем методе вам просто нужно добавить setTimeout, и ваша проблема будет решена.

setTimeout(() => this.inputEl.nativeElement.focus(), 0);