Angular 指令未在最近禁用的输入上正确设置焦点
Angular Directive not setting focus properly on recently disabled input
我有一个输入字段,我想在用户按下 'enter' 键时将其禁用。然后它将尝试获取用户详细信息。当它已获取详细信息或出现错误时,我想再次启用输入字段并将焦点设置在该字段上。
我正在使用此指令将焦点设置在输入字段上:
import { Directive, OnChanges, ElementRef, Input } from '@angular/core';
@Directive({
selector: '[myFocus]'
})
export class FocusDirective implements OnChanges {
@Input('myFocus') isFocused: boolean;
constructor(private hostElement: ElementRef) { }
ngOnChanges() {
if(this.isFocused) {
this.hostElement.nativeElement.focus();
}
}
}
它在 html 中的实现方式如下:
<input type="text" class="form-control" [(ngModel)]="text"
[myFocus]="isFocused" [disabled]="disableInput"
(keydown)="podcastsKeyDown($event)">
podcastKeyDown() 函数如下所示:
podcastsKeyDown(event) {
if(event.keyCode == 13) {
this.disableInput = true;
this.getUser(this.text).subscribe(account => {
this.disableInput = false;
this.isFocused = true;
});
}
}
当用户帐户成功返回后,我将输入字段设置为启用,它工作正常。但是,焦点不会返回到此输入。我试过在重新设置焦点时设置一个超时,以防出现一些时间问题,但这也没有用。代码如下所示:
setTimeout(() => {
this.isPodcastNamesFocused = true;
}, 100);
知道这里发生了什么以及如何解决它吗?
提前致谢。
编辑 1: 准确地说 - 它实际上在第一次使用超时时起作用,但对于后续用户输入它不会...
ngOnChanges
仅当存在纯粹的更改时才有效,这意味着如果您已将 this.isFocused
声明为 true
并且您正在尝试将其再次设置为 true
ngOnChanges
不会触发
尝试这样的事情
@Input('myFocus')
set isFocused(value: boolean) {
if (value) {
this.hostElement.nativeElement.focus();
}
};
或者像这样改变你的指令构造函数constructor(@Host() @Self() private hostElement: ElementRef) { }
刚刚有了一个想法 - 希望它有效
尝试将 reference
变量作为 @Input()
传递并读取它
<input type="text" class="form-control" [(ngModel)]="text" #inputType [element]="inputType"
[myFocus]="isFocused" [disabled]="disableInput"
(keydown)="podcastsKeyDown($event)">
@Input('element') elementType : ElementRef;
现在 elementType
尝试聚焦
希望它有效 - 编码愉快!!
我建议采用以下解决方案。我在本地测试了这段代码。它每次都对我有用。
这里的大部分代码都是为了演示。
指令:
import {Directive, ElementRef, Input} from '@angular/core';
@Directive({
selector: '[myFocus]'
})
export class MyFocusDirective {
// as for me I prefer using setters for properties that have non-trivial logic when being set. They are simple, predictable and robust.
@Input('myFocus')
set isFocused(val: boolean) {
this._isFocused = val;
if (this._isFocused) {
this.hostElement.nativeElement.focus();
}
}
get isFocused(): boolean {
return this._isFocused;
}
_isFocused: boolean;
constructor(private hostElement: ElementRef) { }
}
组件:
import { Component } from '@angular/core';
import {Observable, of, timer} from 'rxjs';
import {map, take} from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
text = 'app';
isFocused: boolean = true;
isDisabled: boolean = false;
userData: {name: string, age: number} = null;
podcastsKeyDown(event) {
if (event.keyCode === 13) {
this.isFocused = false;
this.isDisabled = true;
// take(1) not to have subscriptions hanging around
this.getUser(this.text).pipe(take(1)).subscribe(account => {
this.isDisabled = false;
this.userData = account;
// timeout first makes DOM to render setting isDisabled to false
// when field is enabled we can make it focused
setTimeout(() => {
this.isFocused = true;
});
});
}
}
// some mock data
private getUser(name: string): Observable<{name: string, age: number}> {
return timer(2000).pipe(map(() => {
return {name, age: Math.round(Math.random() * 30 + 10)};
}));
}
}
<input type="text" class="form-control" [(ngModel)]="text"
[myFocus]="isFocused" [disabled]="isDisabled"
(keydown)="podcastsKeyDown($event)">
<p>{{account | json}}</p>
这似乎是通过使用 setTimeout() 函数并记住在获取用户时将焦点设置为 false 来解决的。这一定是导致焦点指令混淆的原因。
podcastsKeyDown(event) {
if(event.keyCode == 13) {
//This is the important line that was missing
this.isFocused = false;
this.disableInput = true;
this.getUser(this.text).subscribe(account => {
this.disableInput = false;
setTimeout(() => {
this.isFocused = true;
});
});
}
}
我有一个输入字段,我想在用户按下 'enter' 键时将其禁用。然后它将尝试获取用户详细信息。当它已获取详细信息或出现错误时,我想再次启用输入字段并将焦点设置在该字段上。
我正在使用此指令将焦点设置在输入字段上:
import { Directive, OnChanges, ElementRef, Input } from '@angular/core';
@Directive({
selector: '[myFocus]'
})
export class FocusDirective implements OnChanges {
@Input('myFocus') isFocused: boolean;
constructor(private hostElement: ElementRef) { }
ngOnChanges() {
if(this.isFocused) {
this.hostElement.nativeElement.focus();
}
}
}
它在 html 中的实现方式如下:
<input type="text" class="form-control" [(ngModel)]="text"
[myFocus]="isFocused" [disabled]="disableInput"
(keydown)="podcastsKeyDown($event)">
podcastKeyDown() 函数如下所示:
podcastsKeyDown(event) {
if(event.keyCode == 13) {
this.disableInput = true;
this.getUser(this.text).subscribe(account => {
this.disableInput = false;
this.isFocused = true;
});
}
}
当用户帐户成功返回后,我将输入字段设置为启用,它工作正常。但是,焦点不会返回到此输入。我试过在重新设置焦点时设置一个超时,以防出现一些时间问题,但这也没有用。代码如下所示:
setTimeout(() => {
this.isPodcastNamesFocused = true;
}, 100);
知道这里发生了什么以及如何解决它吗?
提前致谢。
编辑 1: 准确地说 - 它实际上在第一次使用超时时起作用,但对于后续用户输入它不会...
ngOnChanges
仅当存在纯粹的更改时才有效,这意味着如果您已将 this.isFocused
声明为 true
并且您正在尝试将其再次设置为 true
ngOnChanges
不会触发
尝试这样的事情
@Input('myFocus')
set isFocused(value: boolean) {
if (value) {
this.hostElement.nativeElement.focus();
}
};
或者像这样改变你的指令构造函数constructor(@Host() @Self() private hostElement: ElementRef) { }
刚刚有了一个想法 - 希望它有效
尝试将 reference
变量作为 @Input()
传递并读取它
<input type="text" class="form-control" [(ngModel)]="text" #inputType [element]="inputType"
[myFocus]="isFocused" [disabled]="disableInput"
(keydown)="podcastsKeyDown($event)">
@Input('element') elementType : ElementRef;
现在 elementType
尝试聚焦
希望它有效 - 编码愉快!!
我建议采用以下解决方案。我在本地测试了这段代码。它每次都对我有用。 这里的大部分代码都是为了演示。
指令:
import {Directive, ElementRef, Input} from '@angular/core';
@Directive({
selector: '[myFocus]'
})
export class MyFocusDirective {
// as for me I prefer using setters for properties that have non-trivial logic when being set. They are simple, predictable and robust.
@Input('myFocus')
set isFocused(val: boolean) {
this._isFocused = val;
if (this._isFocused) {
this.hostElement.nativeElement.focus();
}
}
get isFocused(): boolean {
return this._isFocused;
}
_isFocused: boolean;
constructor(private hostElement: ElementRef) { }
}
组件:
import { Component } from '@angular/core';
import {Observable, of, timer} from 'rxjs';
import {map, take} from 'rxjs/operators';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
text = 'app';
isFocused: boolean = true;
isDisabled: boolean = false;
userData: {name: string, age: number} = null;
podcastsKeyDown(event) {
if (event.keyCode === 13) {
this.isFocused = false;
this.isDisabled = true;
// take(1) not to have subscriptions hanging around
this.getUser(this.text).pipe(take(1)).subscribe(account => {
this.isDisabled = false;
this.userData = account;
// timeout first makes DOM to render setting isDisabled to false
// when field is enabled we can make it focused
setTimeout(() => {
this.isFocused = true;
});
});
}
}
// some mock data
private getUser(name: string): Observable<{name: string, age: number}> {
return timer(2000).pipe(map(() => {
return {name, age: Math.round(Math.random() * 30 + 10)};
}));
}
}
<input type="text" class="form-control" [(ngModel)]="text"
[myFocus]="isFocused" [disabled]="isDisabled"
(keydown)="podcastsKeyDown($event)">
<p>{{account | json}}</p>
这似乎是通过使用 setTimeout() 函数并记住在获取用户时将焦点设置为 false 来解决的。这一定是导致焦点指令混淆的原因。
podcastsKeyDown(event) {
if(event.keyCode == 13) {
//This is the important line that was missing
this.isFocused = false;
this.disableInput = true;
this.getUser(this.text).subscribe(account => {
this.disableInput = false;
setTimeout(() => {
this.isFocused = true;
});
});
}
}