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;
}
}
在例子中你可以看到:
- 如果您在
name
输入字段中键入,slug 会在其输入字段中进行转换,但其表单控件值不会进行转换。
- 当您在
slug
输入字段中键入时,它会正常工作,即字段和控件值都会得到转换。
- 将指令添加到名称 FormControl,
- 获取指令中的控件容器
- 获取 Slug 的控制权和 patchValue。
- 删除
("name").onValueChanges()
因为指令会处理它。
问题是 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
我想在用户输入名称控件时转换 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;
}
}
在例子中你可以看到:
- 如果您在
name
输入字段中键入,slug 会在其输入字段中进行转换,但其表单控件值不会进行转换。 - 当您在
slug
输入字段中键入时,它会正常工作,即字段和控件值都会得到转换。
- 将指令添加到名称 FormControl,
- 获取指令中的控件容器
- 获取 Slug 的控制权和 patchValue。
- 删除
("name").onValueChanges()
因为指令会处理它。
问题是 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