角 5 |带有 ControlValueAccessor 的 ReactiveForm |未触发 onChange [英] Angular 5 | ReactiveForm with ControlValueAccessor | onChange is not triggered

查看:22
本文介绍了角 5 |带有 ControlValueAccessor 的 ReactiveForm |未触发 onChange的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义的 ControlValueAccessor,它只是在输入上附加一个货币符号.

I have a custom ControlValueAccessor which simply appends a currency symbol on an input.

@Component({
  selector: 'app-currency-input',
  templateUrl: './currency-input.component.html',
  styleUrls: ['./currency-input.component.scss'],
  providers: [
    CurrencyPipe,
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CurrencyInputComponent),
      multi: true
    }
  ]
})
export class CurrencyInputComponent implements ControlValueAccessor {

  @Input() class = '';

  currencyValue: string;

  onChange: (value: number) => void;
  onTouched: () => void;

  constructor(
    private currencyPipe: CurrencyPipe
  ) { }

  parseToNumber(currencyString: string) {
    this.onChange(this.currencyPipe.parse(currencyString));
  }

  transformToCurrencyString(value: number): string {
    return this.currencyPipe.transform(value);
  }

  writeValue(value: number): void {
    if (value !== undefined) {
      this.currencyValue = this.transformToCurrencyString(value);
    }
  }

  registerOnChange(fn: any): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

}

CurrencyPipe 只是将字符串解析为数字并将数字转换为货币字符串(使用本地化的十进制分隔符和货币符号).

The CurrencyPipe just parses the string to number and transforms a number to a currency string (with localized decimal seperator and currency symbol).


当我尝试像这样使用 ReactiveForms 时:


When I try to use ReactiveForms like this:

<app-currency-input
  name="amount"
  class="value-box"
  formControlName="amount"
  required
></app-currency-input>

... 那么 onChange() 不会在手动输入时触发.

... then onChange() is not triggered on manual input.


我有一个解决方法,我订阅了控件的 valueChanges 然后做一个

control.patchValue(newValue, { emitModelToViewChange: true })

... 成功触发 ControlValueAccessor 的 onChange.(一个没有选项的 patchValue 也会做同样的事情,因为 true 是这个选项的默认值.我只是想在这里指出罪魁祸首.)

... which successfully triggers the onChange for the ControlValueAccessor. (A patchValue without options would do the same, because true is the default value for this option. I just wanted to point out the culprit here.)

但我很想使用一个内置的解决方案,它不会在额外的需要检查和至少两个 valueChanges 中解决.

But I would love to use an inbuilt solution which does not resolve in additional needed checks and at least two valueChanges.


一个简单的 Plunker 来尝试一下:https://embed.plnkr.co/c4YMw87FiZMpN5Gr8w1f/查看 src/app.ts 中注释掉的代码.

A simplified Plunker to try it out: https://embed.plnkr.co/c4YMw87FiZMpN5Gr8w1f/ See the commented out code in src/app.ts.

推荐答案

尝试这样的事情

import { Component, Input, forwardRef } from '@angular/core';
import { CurrencyPipe, } from '@angular/common';
import { ReactiveFormsModule, NG_VALUE_ACCESSOR, FormControl, ControlValueAccessor } from '@angular/forms';
import { Subscription } from 'rxjs/Subscription';

@Component({
  selector: 'currency-input',
  template: `<input [formControl]="formControl" (blur)="onTouched()"/>`,
  styles: [`h1 { font-family: Lato; }`],
  providers: [
    CurrencyPipe,
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => CurrencyInputComponent),
      multi: true
    }
  ]
})
export class CurrencyInputComponent implements ControlValueAccessor {
  constructor(private currencyPipe: CurrencyPipe) { }

  private onChange: Function;
  private onTouched: Function;

  formControl = new FormControl('');
  subscription: Subscription;

  ngOnInit() {
    this.subscription = this.formControl.valueChanges
      .subscribe((v) => {
        this.onChange && this.onChange(this.transform(v));
      })
  }

  ngOnDestroy() {
   this.subscription.unsubscribe();
  }

  writeValue(val) {
    this.formControl.setValue(this.transform(val), { emitEvent: false });
  }

  registerOnChange(fn) {
    this.onChange = fn;
  }

  registerOnTouched(fn) {
    this.onTouched = fn;
  }

  private transform(val: string) {
    return this.currencyPipe.transform(val, 'USD')
  }
}

请注意,我使用的是 ReactiveFormsModule,因此您需要将其导入到您的模块中.

Please note that I'm using the ReactiveFormsModule so you need to import it in your module.

现场演示

这篇关于角 5 |带有 ControlValueAccessor 的 ReactiveForm |未触发 onChange的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆