首页 > 解决方案 > 从 ControlValueAccessor 更改 FormControl 值

问题描述

我正在尝试仅为案例创建一个指令。我创建了以下代码,但尝试制作 formGroup.value 时遇到问题。该指令在视觉上改变了值(通过使用_Renderer2),但formControl仍然具有原始值,并且当使用formGroup.value从表单中获取数据时,值是小写的。有可能解决这个问题吗?谢谢

<form [formGroup]="formGroup">
    <mat-form-field>
        <input placeholder="Street" formControlName="streetName" matInput uppercase>
    </mat-form-field>
</form>

import { Directive, ElementRef, Optional, Renderer2, Self } from '@angular/core';
import { ControlValueAccessor, NgControl } from '@angular/forms';

@Directive({
  selector: "textarea[uppercase], input[uppercase]",
  host: {
    '(input)': 'writeValue($event.target.value)',
    '(blur)': 'onTouched()',
  }
})
export class UppercaseDirective implements ControlValueAccessor {

  onChange = (_: any) => {
    console.log("onChange", _)
  };

  onTouched = () => {
    console.log("onTouched")
  };

  constructor(private _renderer: Renderer2, private _elementRef: ElementRef, @Optional() @Self() public ngControl: NgControl) {
    ngControl.valueAccessor = this;
  }

  writeValue(value: any): void {
    this._renderer.setProperty(this._elementRef.nativeElement, 'value', this.transformValue(value));
  }

  registerOnChange(fn: (_: any) => {}): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: () => {}): void {
    this.onTouched = fn;
  }

  setDisabledState(isDisabled: boolean): void {
    this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
  }

  private transformValue(value: string): string {
    return typeof value === 'string'
      ? value?.toUpperCase()
      : value;
  }
}

标签: angulartypescriptcontrolvalueaccessor

解决方案


您正在混合自定义表单控件和指令的概念。我不知道是否有另一种方法,但是,如果你想制作一个转换一个输入的指令,你可以让它创建一个 HTMLEvent。有些喜欢

@Directive({
  selector: "[toUpperCase]"
})
export class ToUpperCaseDirective implements AfterViewInit {
  constructor(private elementRef: ElementRef) {}

  @HostListener("input", ["$event"]) onKeyDown(event: KeyboardEvent) {
    this.setUpper();
  }
  ngAfterViewInit() {
    setTimeout(() => {
      this.setUpper();
    });
  }
  setUpper() {
    const target = this.elementRef.nativeElement;
    let pos = target.selectionStart; //get the position of the cursor
    target.value = target.value.toUpperCase();
    var evt = document.createEvent("HTMLEvents");
    evt.initEvent("input", false, true);
    this.elementRef.nativeElement.dispatchEvent(evt);
    target.selectionStart = target.selectionEnd = pos; //return the position
  }
}

注意:真的,我不认为该指令是解决大写输入问题的好方法。对我来说最好简单地使用 css

<input style="text-transform:uppercase">

然后,当我们要检查值转换时,使用 toUpperCase。


推荐阅读