Angular 4 监听 setValue 或 patchValue 而不是使用 valueChanges
Posted
技术标签:
【中文标题】Angular 4 监听 setValue 或 patchValue 而不是使用 valueChanges【英文标题】:Angular 4 Listen for setValue or patchValue instead of using valueChanges 【发布时间】:2017-10-26 15:44:59 【问题描述】:我以反应形式向字段添加了一个浮点指令,该指令将逗号添加到每 1000 个字段中,并将.00
附加到字段值,专门用于 UI 中的可读性,效果很好。
当使用现有值加载表单时,我希望对这些值进行格式化,因此我将其添加到浮点指令中,以便在使用setValue
或patchValue
填充表单字段时对值进行一次格式化,效果很好。
浮点指令的片段
public ngOnInit()
this.formatFloat();
private formatFloat()
const handle = this.ngControl.valueChanges
.subscribe((value: string) =>
const float = this.getFloat();
if (float)
this.element.value = this.format(value);
handle.unsubscribe();
);
** 在下面添加了完整的指令,但这只是真正重要的部分。
但是,如果您在填写空表单时将表单字段动态添加到 FormArray,则不会触发一次性格式化,因此您在字段中键入的第一个数字会添加格式。例如,打开一个空表单,单击一个按钮添加一个动态字段,在字段中输入1
会触发一次valueChange
,输入现在有1.00
,用户将继续输入1.001244
而不是11244
。
我知道patchValue
和setValue
通过emitEvent
docs直接链接到valueChanges
,但是有没有办法监听setValue
或patchValue
变化而不是监听@987654337 @?或者是否有另一种方法可以让它工作,但仍然具有现有功能,因为即使只是听 setValue
和 patchValue
也意味着一次性格式订阅仍然有效。
浮点指令
import Directive, HostListener, ElementRef, OnInit from '@angular/core';
import DecimalPipe from '@angular/common';
import FormGroup, NgControl from '@angular/forms';
@Directive(
selector: '[cfFloat]',
providers: [DecimalPipe] // TODO: why do I need this?
)
export class FloatDirective implements OnInit
public element: htmlInputElement;
constructor(
private elementRef: ElementRef,
private decimalPipe: DecimalPipe,
private ngControl: NgControl
)
this.element = this.elementRef.nativeElement;
@HostListener('blur', ['$event'])
onBlur(event: KeyboardEvent)
const float = this.getFloat();
if (float)
this.element.value = this.format(float);
@HostListener('focus', ['$event'])
onFocus(event: KeyboardEvent)
const float = this.getFloat();
if (float)
this.element.value = this.replace(float);
public ngOnInit()
this.formatFloat();
private formatFloat()
const handle = this.ngControl.valueChanges
.subscribe((value: string) =>
const float = this.getFloat();
if (float)
this.element.value = this.format(value);
handle.unsubscribe();
);
private getFloat(): string
const value = this.element.value;
const float = this.replace(value);
// Only perform an action when a floating point value exists and there are
// no errors, otherwise leave the erroneous value to be fixed manually by
// ignoring an action
if (value && float && this.checkIsValid())
return float;
private checkIsValid(): boolean
return !this.ngControl.control.errors;
private replace(value: string): string
return value.replace(/[^\d\.]+/g, '');
private format(value: string)
return this.decimalPipe.transform(value, '1.2-2');
【问题讨论】:
【参考方案1】:好的,想通了。不是一个可怕的修复,但似乎它可能会更优雅......总是提出建议。
private onInitFormatHandler: Subscription; // <-- ADDED HANDLER AS MEMBER VARIABLE INSTEAD
@HostListener('focus', ['$event'])
onFocus(event: KeyboardEvent)
// Remove initial formatting subscription since no patch of the value has
// occurred, and is no longer likely to occur if the user is actively
// applying focus
// ---
// NOTE: Not unsubscribing causes formatting to occur on dynamically added
// fields on the first change of the input value prior to blur
if (!this.onInitFormatHandler.closed) // <-- ADDED CHECK AND EXTRA UNSUBSCRIPTION
this.onInitFormatHandler.unsubscribe();
const float = this.getFloat();
if (float)
this.element.value = this.replace(float);
public ngOnInit()
this.formatFloat();
/**
* Format the input value only once after the initial form response has
* patched the model.
* ---
* NOTE: Format handler is stored and unsubscribed either on valueChange, or
* if focus is applied to the field, whichever occurs first.
*/
private formatFloat()
this.onInitFormatHandler = this.ngControl.valueChanges // <-- UPDATED HANDLER TO BE MEMBER VARIABLE
.subscribe((value: string) =>
const float = this.getFloat();
if (float)
this.element.value = this.format(value);
this.onInitFormatHandler.unsubscribe(); // <-- UPDATED HANDLER TO BE MEMBER VARIABLE
);
【讨论】:
以上是关于Angular 4 监听 setValue 或 patchValue 而不是使用 valueChanges的主要内容,如果未能解决你的问题,请参考以下文章