3

尝试替换输入的特殊字符,我最终编写了这个简单的指令:

标准化输入.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");
  }
}

这将替换abon keypress。这是我的示例(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)

StackBlitz

4

2 回答 2

2

如果您仍然想通过处理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'));
  }
}

分叉的 Stackblitz

于 2020-12-23T20:47:36.517 回答
1

您应该使用 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));
  }
}

StackBlitz

于 2020-12-23T20:40:08.283 回答