Reputation: 1263
In my app, I tried to place a button that shows/hides an input
field with a boolean
component property. If the button shows the input
, focus should be set on the input
. But it seems not to work. If I remove the *ngIf
the focus directive works fine.
I created a plunker that shows what I mean. It's kind of difficult to describe my problem.
HTML in a component:
<input *ngIf="filterShow.options"
[focus]="filterFocus.options"
[(ngModel)]="filter.options">
<button type="button"
(click)="setShowFilter('options')">
focus
</button>
setShowFilter()
method:
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', []);
});
}
}
Upvotes: 10
Views: 9203
Reputation: 3671
EventEmitter
s are for @Output
s, not for @Input
s. Try something like this instead:
@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', []);
}
}
}
Upvotes: 9
Reputation: 300
Most of the time, it doesn't work because the focus event is followed by other events. So the element lost focus. We need to use setTimeout
in order to put it at the end of the Task Scheduler queue:
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);
}
}
}
Upvotes: 3
Reputation: 41
A cleaner way to achieve this without having to use a directive is to use <label>
instead of <button>
and use css to style it like a button. For example,
<label for="myInput"></label>
<input id="myInput"></input>
This way you can achieve focus even with the presence of *ngIf
because the <input>
is now bound to the <label>
. Also, Angular2 documentation website warns about the use of ElementRef
because of the security vulnerability it poses.
Upvotes: 1