*ngIf 带有焦点指令

*ngIf with focus directive

在我的应用程序中,我尝试放置一个按钮,该按钮 shows/hides 一个带有 boolean 组件 属性 的 input 字段。如果按钮显示 input,则应将焦点设置在 input 上。但它似乎不起作用。如果我删除 *ngIf 焦点指令工作正常。

我创建了一个 plunker 来表达我的意思。描述我的问题有点困难。

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', []);
    });
  }
}

EventEmitters 适用于 @Outputs,不适用于 @Inputs。尝试这样的事情:

@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', []);
    }
  }
}

无需使用指令即可实现此目的的更简洁方法是使用 <label> 而不是 <button> 并使用 css 将其设置为按钮样式。例如,

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

即使 *ngIf 存在,您也可以通过这种方式获得焦点,因为 <input> 现在已绑定到 <label>Also, Angular2 documentation website warns about the use of ElementRef because of the security vulnerability it poses.

大多数情况下,它不起作用,因为焦点事件之后有其他事件。所以元素失去了焦点。我们需要使用 setTimeout 以便将其放在 Task Scheduler 队列的末尾:

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);      
    }
  }
}