angular: 表单控件的指令转换值

angular: directive transform value of form control

我想在用户输入名称控件时转换 slug 控件。 我正在应用转换,例如将空格更改为连字符 (-) 等

我为此创建了一个部分有效的指令。它确实会转换 slug 输入字段的值,但在输入名称时不会更改 slug 表单控件的值。

这是实时代码: https://stackblitz.com/edit/angular-slug-transform

指令:

import { Directive, HostListener } from "@angular/core";
import { NgControl } from "@angular/forms";

@Directive({
  selector: "[formControlName][appSlugTransform]"
})
export class SlugTransformDirective {
  constructor(public ngControl: NgControl) {}

  @HostListener("ngModelChange", ["$event"])
  onModelChange(event) {
    let newVal = this.transform(event);
    this.ngControl.valueAccessor.writeValue(newVal);
  }

  transform(value) {
    let text = value.toLowerCase();
    if (text.charAt(0) == " ") {
      text = text.trim();
    }
    if (text.charAt(text.length - 1) == "-") {
      //text = (text.replace(/-/g, ""));
    }
    text = text.replace(/ +/g, "-");
    text = text.replace(/--/g, "-");
    text = text.normalize("NFKD").replace(/[\u0300-\u036f]/g, ""); // Note: Normalize('NFKD') used to normalize special alphabets like óã to oa
    text = text.replace(/[^a-zA-Z0-9 -]/g, "");

    return text;
  }
}

在例子中你可以看到:

  1. 将指令添加到名称 FormControl,
  2. 获取指令中的控件容器
  3. 获取 Slug 的控制权和 patchValue。
  4. 删除 ("name").onValueChanges() 因为指令会处理它。

https://stackblitz.com/edit/angular-slug-transform-zbkdwv

问题是 this.ngControl.valueAccessor.writeValue(newVal) 没有触发模型更新。不确定为什么会这样,但这里有一种替代方法,您可以使用 ElementRef & dispatchEvent 来触发模型更新:

首先使用 ElementRef 更新输入值,然后使用 dispatchEvent

this.el.value = newVal;
this.el.dispatchEvent(new Event('input'))

演示:https://stackblitz.com/edit/angular-slug-transform-sdmeto



完整更新指令:

import { Directive, HostListener, ElementRef, OnInit } from "@angular/core";
import { NgControl } from "@angular/forms";

@Directive({
  selector: "[formControlName][appSlugTransform]"
})
export class SlugTransformDirective implements OnInit {
  private el: any;

  constructor(public ngControl: NgControl, private elementRef: ElementRef) {
    this.el = this.elementRef.nativeElement;
  }

  ngOnInit() {
    this.el.value = this.transform(this.el.value);
  }

  @HostListener("ngModelChange", [ "$event"])
  onNgModelChange(event) {
    let newVal = this.transform(event);
    // this.ngControl.valueAccessor.writeValue(newVal);
    this.el.value = newVal;
    this.el.dispatchEvent(new Event('input'))
  }

  transform(value) {
    let text = value.toLowerCase();
    if (text.charAt(0) == " ") {
      text = text.trim();
    }
    if (text.charAt(text.length - 1) == "-") {
      //text = (text.replace(/-/g, ""));
    }
    text = text.replace(/ +/g, "-");
    text = text.replace(/--/g, "-");
    text = text.normalize("NFKD").replace(/[\u0300-\u036f]/g, ""); // Note: Normalize('NFKD') used to normalize special alphabets like óã to oa
    text = text.replace(/[^a-zA-Z0-9 -]/g, "");

    return text;
  }
}

您可以尝试的另一种方法是使用 patchValue 而不是 writeValue,如下所示:

this.ngControl.control.patchValue(newVal);

那应该会触发模型更改。 (未测试)

问题终于解决了,神奇的地方来了

ngOnInit(): void {
  this.valueSubscription = this.ngControl.control.valueChanges.subscribe(
    value => {
      const newVal = this.transform(value);
      this.ngControl.control.setValue(newVal, { emitEvent: false });
    }
  );
}

我正在使用 valueChanges 而不是 HostListener 来监听值变化。

为了更新值,我现在使用 setValue 控制方法。

这里是 运行 代码:https://stackblitz.com/edit/angular-slug-directive