Angular 12+: Is there a Simple way to apply display mask/pipe for Reactive Form?

Viewed 111

Reactive form, if user-input from keyboard is 1000000 expects to see 10,000.00. So a pipe is needed. Found a few SO posts,

Seems like have to add some code to subscribe for value change event, no simple way?

<form [formGroup]="fg">
    <input
        type="number"
        class="fc"
        placeholder="integer"
        formControlName="fcTest"
        id="fcTest"
        [value]="fg.get('fcTest').valueChanges |async | number: '9.2.2'"
    />
</form>
fg: FormGroup;
    
constructor(private fb: FormBuilder) {
    this.fg = this.fb.group({
        fcTest: ['', [Validators.required]]
    });
}
3 Answers

In the Video

I think what is shown in the video is actually a rather clean and elegant solution:

ngOnInit() {
  this.fg.valueChanges.subscribe(form => {
    this.fg.patchValue({
      money: this.currencyPipe.transform(form.money.replace(/\D/g, '').replace(/^0+/, ''), 'EUR', 'symbol', '1.0-0')
    }, {emitEvent: false})
  })
}

Minor Simplification

You can avoid having to subscribe to valueChanges in the OnInit by binding an event in the template:

<form [formGroup]="fg">
    <input
      (keyup)="onChange()"
      type="text"
      class="money"
      placeholder="€"
      formControlName="money"
      id="money"
    />
</form>

And what onChange() would look like:

onChange() {
  this.fg.patchValue({
    money: this.currencyPipe.transform(this.fg.value.money.replace(/\D/g, '').replace(/^0+/, ''), 'EUR', 'symbol', '1.0-0')
  }, {emitEvent: false})
}

Here is the above example in a Stackblitz.

If your attempt with [value]="fg.get('fcTest').value | number: '9.2-2'" is giving errors in the IDE, try moving part of it to a function and use typings e.g

// template
[value]="fcTestValue | number: '9.2-2'"

// component
get fcTestValue(): string {
   return (this.fc.get('fcTest')?.value || '') as string;
}

All three quoted solutions should work, however the error you invoke says that the control is undefined or comes null as of data, so value property cannot be applied to null. It is accessing the property of null, which obviously a reason to throw an error. You can either type define the control, either, going by shortcut way, use optional chaining operator (?.)

[value]="fg.get('fcTest')?.value | number: '9.2-2'"

One other solution could be:

@input #fcTest
    ...
    
    [value]="fcTest.value | number: '9.2.2'" >
Related