【发布时间】:2019-03-19 11:56:08
【问题描述】:
我在 Angular 中有一个实现 ControlValueAccessor 的指令。除了获取在 FormControl.setValue() 中设置的值之外,该指令似乎还在起作用。如何在指令中获取该值更新?
这是我的指令
import {
Directive,
ElementRef,
EventEmitter,
forwardRef,
HostListener,
Input,
Output,
Renderer2
} from '@angular/core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
import {CurrencyPipe} from '@angular/common';
@Directive({
selector: '[currency-input]',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CurrencyInputDirective),
multi: true
}
]
})
export class CurrencyInputDirective implements ControlValueAccessor {
// TODO: Allow null value
_currencyString: string = '';
@Input() ciDecimals = 2;
@Input() ciCurrencyCode = 'USD';
@Input() ciMaximumAmount = 10000;
// Pass true if using formControl or formControlName
@Input() ciModelDrivenForm = false;
@Output() ciExceededMax: EventEmitter<any> = new EventEmitter();
onChangeCallback = (_: any) => {};
onTouchedCallback = () => {};
@HostListener('onNgModelChange') onNgModelChange() {
// Never runs
console.log("in ng model change");
}
@HostListener('input', ['$event']) onInput(value: any) {
// Never runs
console.log("in input");
}
@HostListener('blur', []) onBlur() {
this.onTouchedCallback();
}
@HostListener('focus', []) onFocus() {
this.onTouchedCallback();
}
@HostListener('keydown', ['$event']) onKeyDown(e: KeyboardEvent) {
switch (e.key) {
case 'Backspace':
this.handleBackspaceKeyPress(e);
break;
default:
if (isNaN(+e.key)) {
e.preventDefault();
} else {
this.handleNumericKeyPress(e);
}
break;
}
}
constructor (
private _renderer: Renderer2,
private _elementRef: ElementRef,
private _currencyPipe: CurrencyPipe
) {}
writeValue(value: any) {
this._renderer.setProperty(this._elementRef.nativeElement, 'value', this.buildElementValue());
this.onChangeCallback(this.buildControlValue());
}
registerOnChange(fn: any) {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any) {
this.onTouchedCallback = fn;
}
setDisabledState(isDisabled: boolean) {
this._renderer.setProperty(this._elementRef.nativeElement, 'disabled', isDisabled);
}
private handleBackspaceKeyPress(e: KeyboardEvent) {
e.preventDefault();
// Remove one digit
if (this._currencyString.length > 0) {
this._currencyString = this._currencyString.slice(0, this._currencyString.length - 1);
}
this.writeValue(this._currencyString);
}
private handleNumericKeyPress(e: KeyboardEvent) {
e.preventDefault();
const newCurrencyString = this._currencyString + e.key;
const currencyValue: number = this.convertCurrencyStringToCurrencyValue(newCurrencyString);
if (currencyValue > this.ciMaximumAmount) {
setTimeout(() => {
this.ciExceededMax.emit({ amount: currencyValue, maxAmount: this.ciMaximumAmount });
}, 1);
return;
}
this._currencyString = newCurrencyString;
this.writeValue(this._currencyString);
}
private buildElementValue() {
const currencyDecimals = '1.' + this.ciDecimals + '-' + this.ciDecimals;
const retVal: string = !this._currencyString ? null : this._currencyPipe.transform(
this.convertCurrencyStringToCurrencyValue(this._currencyString),
this.ciCurrencyCode,
'symbol',
currencyDecimals);
return retVal ? retVal : this._currencyPipe.transform(0, this.ciCurrencyCode, 'symbol', currencyDecimals);
}
private buildControlValue() {
return this.convertCurrencyStringToCurrencyValue(this._currencyString);
}
private convertCurrencyValueToCurrencyString(currencyValue: number): string {
return currencyValue.toString().replace(/[^0-9]/g, '');
}
private convertCurrencyStringToCurrencyValue(currencyString: String): number {
const strippedValue: string = currencyString.replace(/[^0-9]/g, '');
if (strippedValue.length === 0) {
return 0;
}
const parsedInt: number = parseInt(strippedValue, 10);
return parsedInt / Math.pow(10, this.ciDecimals);
}
}
这是我的 setValue()
myForm.get('myField').setValue(5.00);
【问题讨论】:
-
onChangeCallback将在每次值更改时被调用。如果你想使用其他东西,你可以使用注入器来获取NgControl依赖,它包含一个control,它是一个具有valueChanges属性的抽象控件。 -
实际上,writeValue 将被调用新值。我不知道为什么我从来没有想过。
标签: angular angular-reactive-forms angular-directive