我有一个指令,如果输入值是整数,则在模糊时附加小数。下面是实现。
import { Directive, ElementRef, Input, OnInit, HostListener, forwardRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Directive({
selector: '[price]',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => PriceDirective),
multi: true
}
]
})
export class PriceDirective implements ControlValueAccessor {
constructor(private el: ElementRef) { }
// ControlValueAccessor interface
private _onChange = (_) => { };
private _onTouched = () => { };
@HostListener('blur', ['$event'])
input(event) {
!!event.target.value ? $(this.el.nativeElement).val(Number(event.target.value).toFixed(2)) : $(this.el.nativeElement).val(null);
this._onChange(parseFloat(event.target.value));
this._onTouched();
}
writeValue(value: any): void {
!!value ? $(this.el.nativeElement).val(Number(value).toFixed(2)) : $(this.el.nativeElement).val(null);
}
registerOnChange(fn: (_: any) => void): void { this._onChange = fn; }
registerOnTouched(fn: any): void { this._onTouched = fn; }
}
事情按预期工作。
但是,由于 Angular 在以编程方式更改值时不会触发验证,因此不会验证具有此指令的文本框。
在这种情况下,除了将control
引用作为指令的输入传递并在其上调用updateValueAndValidity
,或在input
或blur
上调用updateValueAndValidity
之外,如何通过其他方式启用验证。
如果有人向我建议一种从指令本身触发验证的方法,那就太好了。
我以这种方式解决了同样的问题。这是我的第一个方法。
update() {
// ...
const el = this.el.nativeElement;
const reg = new RegExp(this.textMaskConfig.replacement);
el.value = this.prevStr.replace(reg, this.currentChar);
// ...
}
但它不会触发验证事件。所以我得到了NgControl
组件并使用setValue()
方法。
constructor(private el: ElementRef, private ctrl: NgControl) {
}
@HostListener('keydown', ['$event']) onKeyDownHandler(e) {
this.ctrl.control.setValue(value);
}
我解决了我认为是同样的问题。 当我像您的示例中那样在 nativeElement 上设置值或使用 HostBinding 设置为像 @HostBinding('value') public value: string;
这样的值时,我无法触发验证。 但是当我通过 ngModelChange 设置值时,我可以像这样触发验证:
import { Directive, Input, HostListener, Output, EventEmitter } from '@angular/core';
@Directive({
selector: '[appPrice]',
})
export class PriceDirective {
@Output()
public ngModelChange: EventEmitter<any> = new EventEmitter();
@HostListener('blur', ['$event.target.value'])
public formatANumber(value) {
const cleanedValue = Number(value).toFixed(2);
this.ngModelChange.emit(cleanedValue);
}
}
不清楚您要添加什么验证。据我了解,您希望从指令中访问形式的输入元素,并根据某些逻辑对其进行操作。我将向您展示 rx 的一种方式.js根据您的验证逻辑,您可以使用相应的运算符。
在生成的指令文件中:
import { Directive, ElementRef } from '@angular/core';
import { NgControl } from '@angular/forms';
import { map } from 'rxjs/operators';
@Directive({
selector: '[appPrice]',
})
export class PriceDirective {
// dependency injection for ElementRef has to set in the constructor
constructor(private el: ElementRef, private controlName: NgControl) {
console.log(this.el);
console.log('controlName', controlName);
// this returns FormControlName (not FormControl) obj. it has name property that tells u which formCpntrol element u r on.
// FormContolName class binds the FormControl to the "input" element. FormControlName has no direct reference to FormGroup
// controlName is bound to input element's formGroup's FormGroup
}
ngOnInit() {
console.log(this.controlName.control);
// this returns the name of the formControl
console.log(this.controlName.control.parent);
// this.controlName.control.parent takes us to the FormGroup
// this.controlName.control.parent returns observable. valueChanges watches all the formControls that you defined. if you have "a","b","c" formControls
// with pipe() you can add operators to modify the value
this.controlName.control.parent.valueChanges
.pipe(map(({ a, b, c }) => // add Some Logic here))
.subscribe((value) => {
if (here is True) {
this.el.nativeElement.classList.add('close');
} else {
this.el.nativeElement.classList.remove('close');
}
});
}
}