nativeElement.Value 指令更改目前未反映在 input/ngModelChange 事件中
nativeElement.Value changes in directive not being reflected for input/ngModelChange events at the moment
试图替换输入的特殊字符,我最终写了这个简单的指令:
归一化-input.directive.ts
@Directive({
selector: "[appNormalizedInput]"
})
export class NormalizedInputDirective {
constructor(private element: ElementRef) {}
@HostListener("keypress", ["$event"]) replaceAWithB(event): void {
const initalValue: string = this.element.nativeElement.value;
this.element.nativeElement.value = initalValue.replace("a", "b");
}
}
这会在按键时将 a
替换为 b
。这是我的样本 (StackBlitz):
app.component.html
<input type="text" (input)="onInput($event)" [(ngModel)]="model" (ngModelChange)="onModelChange()" appNormalizedInput/>
<br/>
<label>{{model}}</label>
app.component.ts
export class AppComponent {
model = "";
onInput(event) {
console.log("on input: ", event.target.value);
}
onModelChange() {
console.log("On model change: ", this.model);
}
}
一旦我输入 a
,我希望在控制台输出中出现 b
,model
(标签内容)也是如此,但是我得到 a
直到下一个键被按下。
问题是事件是 one step behind
输入的实际 UI 值。
处理这种情况的正确 HostListener 事件 是什么?我应该如何更改该值,以便我可以在 (input)
和 (ngModelChange)
事件中获得新值?
您应该使用 ngControl 并使用您想要的代理函数包装 onChange 事件,如下所示:
@Directive({
selector: "[myDirective]"
})
export class Mydirective {
constructor(private ngControl: NgControl) {}
ngOnInit() {
const initialOnChange = (this.ngControl.valueAccessor as any).onChange;
(this.ngControl.valueAccessor as any).onChange = value =>
initialOnChange(this.processInput(value));
}
processInput(value: any) {
return value.replace("a", "b");
}
@HostListener("ngModelChange", ["$event"])
ngModelChange(value: any) {
this.ngControl.valueAccessor.writeValue(this.processInput(value));
}
}
如果您仍然想通过处理 keypress
事件来完成它,并且还想 在键入时保留光标位置 那么您可以尝试这个选项:
@HostListener("keypress", ["$event"]) replaceAWithB(e): void {
if (e.key === 'a') {
const { selectionStart: start, selectionEnd: end, value: oldValue } = e.target;
e.target.value = oldValue.slice(0, start) + 'b' + oldValue.slice(end);
e.target.selectionStart = e.target.selectionEnd = start + 1;
e.preventDefault();
e.target.dispatchEvent(new KeyboardEvent('input'));
}
}
试图替换输入的特殊字符,我最终写了这个简单的指令:
归一化-input.directive.ts
@Directive({
selector: "[appNormalizedInput]"
})
export class NormalizedInputDirective {
constructor(private element: ElementRef) {}
@HostListener("keypress", ["$event"]) replaceAWithB(event): void {
const initalValue: string = this.element.nativeElement.value;
this.element.nativeElement.value = initalValue.replace("a", "b");
}
}
这会在按键时将 a
替换为 b
。这是我的样本 (StackBlitz):
app.component.html
<input type="text" (input)="onInput($event)" [(ngModel)]="model" (ngModelChange)="onModelChange()" appNormalizedInput/>
<br/>
<label>{{model}}</label>
app.component.ts
export class AppComponent {
model = "";
onInput(event) {
console.log("on input: ", event.target.value);
}
onModelChange() {
console.log("On model change: ", this.model);
}
}
一旦我输入 a
,我希望在控制台输出中出现 b
,model
(标签内容)也是如此,但是我得到 a
直到下一个键被按下。
问题是事件是 one step behind
输入的实际 UI 值。
处理这种情况的正确 HostListener 事件 是什么?我应该如何更改该值,以便我可以在 (input)
和 (ngModelChange)
事件中获得新值?
您应该使用 ngControl 并使用您想要的代理函数包装 onChange 事件,如下所示:
@Directive({
selector: "[myDirective]"
})
export class Mydirective {
constructor(private ngControl: NgControl) {}
ngOnInit() {
const initialOnChange = (this.ngControl.valueAccessor as any).onChange;
(this.ngControl.valueAccessor as any).onChange = value =>
initialOnChange(this.processInput(value));
}
processInput(value: any) {
return value.replace("a", "b");
}
@HostListener("ngModelChange", ["$event"])
ngModelChange(value: any) {
this.ngControl.valueAccessor.writeValue(this.processInput(value));
}
}
如果您仍然想通过处理 keypress
事件来完成它,并且还想 在键入时保留光标位置 那么您可以尝试这个选项:
@HostListener("keypress", ["$event"]) replaceAWithB(e): void {
if (e.key === 'a') {
const { selectionStart: start, selectionEnd: end, value: oldValue } = e.target;
e.target.value = oldValue.slice(0, start) + 'b' + oldValue.slice(end);
e.target.selectionStart = e.target.selectionEnd = start + 1;
e.preventDefault();
e.target.dispatchEvent(new KeyboardEvent('input'));
}
}