Angular2 с использованием *ngIf с директивой focus?

В моем приложении я попытался разместить кнопку, которая показывает / скрывает поле ввода с логическим свойством компонента. Если кнопка показывает вход, фокус должен быть установлен на входе. Но, похоже, не работает. Если я удалю *ngIf директива фокусировки работает отлично.

Я создал поршень, который показывает, что я имею в виду. Трудно описать мою "проблему".

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

<input *ngIf="filterShow.options"
       [focus]="filterFocus.options"
       [(ngModel)]="filter.options">

<button type="button"
        (click)="setShowFilter('options')">
  focus
</button>

функция setShowFilter ()

private setShowFilter(filter: string) {
  this.filterShow[filter] = !this.filterShow[filter];

  /* reset filter */
  this.filter[filter] = "";

  this.filterFocus[filter].emit(true);
}

focus.directive.ts

@Directive({
  selector: '[focus]'
})
export class FocusDirective implements OnInit {

  @Input('focus') focusEvent: EventEmitter<boolean>;

  constructor(private elementRef : ElementRef,
              private renderer   : Renderer   ) { }

  ngOnInit() {
    this.focusEvent.subscribe(event => {
      this.renderer
        .invokeElementMethod(this.elementRef.nativeElement, 'focus', []);
    });
  }
}

3 ответа

Решение

EventEmitters для выходов, а не для входов. Попробуйте что-то вроде этого:

@Directive({
  selector: '[focus]'
})
export class FocusDirective implements OnChanges {

  @Input('focus') focus: boolean;

  constructor(private elementRef : ElementRef,
              private renderer   : Renderer   ) { }

  ngOnChanges() {
    if (this.focus) {
      this.renderer
        .invokeElementMethod(this.elementRef.nativeElement, 'focus', []);
    }
  }
}

В большинстве случаев это не работает, потому что за событием фокуса следуют другие события. Таким образом, элемент потерял фокус. Нам нужно использовать setTimeout чтобы поместить его в конец очереди планировщика задач:

import { Directive, OnChanges, Input, ElementRef } from "@angular/core";

@Directive({
  selector: '[focus]'
})
export class FocusDirective implements OnChanges {
  @Input('focus') focus: boolean;

  constructor(private elementRef : ElementRef) { }

  ngOnChanges() {
    if (this.focus) {
      setTimeout(() => { this.elementRef.nativeElement.focus(); }, 0);      
    }
  }
}

Более чистый способ достичь этого без использования директивы - это использовать <label> вместо <button> и используйте CSS, чтобы оформить его как кнопку. Например,

<label for="myInput"></label> <input id="myInput"></input>

Таким образом, вы можете достичь фокуса даже при наличии *ngIf поскольку <input> теперь связан с <label>, Кроме того, веб-сайт документации Angular2 предупреждает об использовании ElementRef из-за уязвимости безопасности, которую он представляет.

Другие вопросы по тегам