我在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);
答案 0 :(得分:0)
结果表明,在调用FormControl.setValue()时正在调用writeValue。这是更新的指令,以防任何人使用。
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';
import {isNullOrUndefined} from '../../util';
@Directive({
selector: '[currencyInput]',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CurrencyInputDirective),
multi: true
}
]
})
export class CurrencyInputDirective implements ControlValueAccessor {
private _currencyString: string = '';
@Input() ciDecimals = 2;
@Input() ciCurrencyCode = 'USD';
@Input() ciMaximumAmount = 10000;
@Input() ciAllowNull = false;
@Output() ciExceededMax: EventEmitter<any> = new EventEmitter();
onChangeCallback = (value: any) => {
};
onTouchedCallback = () => {
};
@HostListener('blur', []) onBlur() {
this.onTouchedCallback();
}
@HostListener('focus', []) onFocus() {
this.onTouchedCallback();
}
@HostListener('keydown', ['$event']) onKeyDown(e: KeyboardEvent) {
switch (e.key) {
case 'Tab':
// Allow default
break;
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) {
const currencyString: string = this.convertCurrencyValueToCurrencyString(value);
if (currencyString !== this._currencyString) {
const currencyValue: number = this.convertCurrencyStringToCurrencyValue(currencyString);
if (currencyValue > this.ciMaximumAmount) {
setTimeout(() => {
this.ciExceededMax.emit({amount: currencyValue, maxAmount: this.ciMaximumAmount});
}, 1);
return;
}
this._currencyString = currencyString;
}
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();
this.writeValue((this._currencyString.length === 0) ? this._currencyString : this._currencyString.slice(0, this._currencyString.length - 1));
}
private handleNumericKeyPress(e: KeyboardEvent) {
e.preventDefault();
this.writeValue(this._currencyString + e.key);
}
private buildElementValue() {
const currencyDecimals = '1.' + this.ciDecimals + '-' + this.ciDecimals;
const controlValue: number = this.buildControlValue();
// Currency format return value
if (!isNullOrUndefined(controlValue)) {
return this._currencyPipe.transform(
controlValue,
this.ciCurrencyCode,
'symbol',
currencyDecimals);
}
return '';
}
private buildControlValue(): number {
return this.convertCurrencyStringToCurrencyValue(this._currencyString);
}
private convertCurrencyValueToCurrencyString(currencyValue: any): string {
if (isNullOrUndefined(currencyValue)) {
return '';
}
if (typeof currencyValue === 'number') {
const currencyDecimals = '1.' + this.ciDecimals + '-' + this.ciDecimals;
currencyValue = this._currencyPipe.transform(currencyValue, this.ciCurrencyCode, 'symbol', currencyDecimals);
}
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 (this.ciAllowNull) ? null : 0;
}
const parsedInt: number = parseInt(strippedValue, 10);
return parsedInt / Math.pow(10, this.ciDecimals);
}
}