nativeElement выбирает ожидание привязки данных - PullRequest
0 голосов
/ 18 января 2019

Допустим, у меня есть дочерний компонент с именем inputComponent, который имеет один элемент ввода, как следует

@Component({ template: `<input #count [(ngModel)]="item.count" />`})
export class inputComponent implements OnInit {

    @Input item;
    @ViewChild("count") count : ElementRef ; 


    focus(){
       this.count.nativeElement.focus();
       this.count.nativeElement.select();
    }

 }

и я включаю его в родительский контейнер следующим образом

<app-input-component [item]="item" ></app-input-component>

То, чего я пытаюсь добиться, - это выбрать текстовый ввод для определенного события. например

@ViewChild("input") count : inputComponent ; 
foo(){
this.item = item ; 
this.count.focus();
}

Проблема в том, что когда я вызываю изменение фокуса сразу после изменения данных привязки (элемента), он не выбирает ничего, если я позвонил focus() после короткого времени ожидания, он работает отлично.

Я знаю, что это не правильный способ использовать setTimeOut для ее решения.

URL-адрес Stackblitz

https://stackblitz.com/edit/angular-svgmtg

Ответы [ 2 ]

0 голосов
/ 18 января 2019

Очевидно, ngModel обновляет значение представления асинхронно при изменении модели.Т.е. значение <input> не изменяется до следующего цикла обнаружения изменений!

Из исходного кода ngModel :

/**
 * `ngModel` forces an additional change detection run when its inputs change:
 * E.g.:
 * ```
 * <div>{{myModel.valid}}</div>
 * <input [(ngModel)]="myValue" #myModel="ngModel">
 * ```
 * I.e. `ngModel` can export itself on the element and then be used in the template.
 * Normally, this would result in expressions before the `input` that use the exported directive
 * to have and old value as they have been
 * dirty checked before. As this is a very common case for `ngModel`, we added this second change
 * detection run.
 *
 * Notes:
 * - this is just one extra run no matter how many `ngModel` have been changed.
 * - this is a general problem when using `exportAs` for directives!
 */
const resolvedPromise = Promise.resolve(null);

Затем, когда модельобновлено, представление обновлено асинхронно :

private _updateValue(value: any): void {
  resolvedPromise.then(
      () => { this.control.setValue(value, {emitViewToModelChange: false}); });
}

Таким образом, setTimeout гарантировал, что вход был выбран после того, как его представление было обновлено.

Если вы хотите избежать этогоасинхронное поведение, вы можете использовать FormControl вместо ngModel ( Demo StackBlitz ):

import { Component, Input, ViewChild, ElementRef } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'hello',
  template: `<input #input [formControl]="count" />`,
  styles: [`h1 { font-family: Lato; }`]
})
export class HelloComponent {
  private _item;

  @Input() set item(value) {
    this._item = value;
    this.count.setValue(value.count);
    this.focus();
  }

  get item() {
    return this._item;
  }

  @ViewChild('input') input: ElementRef;

  count = new FormControl();

  focus() {
    this.input.nativeElement.focus();
    this.input.nativeElement.select();
  }
}

При таком подходе вам не нужно явно вызывать focus() изродительский компонент;дочерний компонент будет вызывать свой собственный метод фокуса при каждом изменении ввода.

0 голосов
/ 18 января 2019

Как я понял, вы пытаетесь получить элемент до его визуализации. Это невозможно. Я советую вам прочитать о крюках Lifecycle в Angular. https://angular.io/guide/lifecycle-hooks

Вы можете решить эту проблему, вызвав функцию foo () в хуке жизненного цикла - ngAfterViewInit.

ngAfterViewInit() {
   this.foo();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...