How to use pipes in Angular 5 reactive form input

angular2 reactive forms currency pipe
angular reactive form currency input
angular reactive forms currency format
reactive forms pipes
angular currency pipe
angular reactive form table
angular form array value changes
angular reactive forms calculated field

I am trying to figure out how to use a pipe within a reactive form so that the input is forced into a currency format. I have already created my own pipe for this which I have tested in other areas of the code so I know it works as a simple pipe. My pipe name is 'udpCurrency'

The closest answer I could find on stack overflow was this one: Using Pipes within ngModel on INPUT Elements in Angular2-View However this is not working in my case and I suspect it has something to do with the fact that my form is reactive

Here is all the relevant code:

The Template

<form [formGroup]="myForm" #f="ngForm">
  <input class="form-control col-md-6" 
    formControlName="amount" 
    [ngModel]="f.value.amount | udpCurrency" 
    (ngModelChange)="f.value.amount=$event" 
    placeholder="Amount">
</form>

The component

import { Component, OnInit, HostListener } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

export class MyComponent implements OnInit {
  myForm: FormGroup;

  constructor(
    private builder: FormBuilder
  ) {
    this.myForm = builder.group({
      amount: ['', Validators.required]
    });
  }    
}

The error:

ERROR Error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined: '. Current value: 'undefined: undefined'

This is what can happen when you mix template driven form and reactive form. You have two bindings fighting each other. Choose either template driven or reactive form. If you want to go the reactive route, you can use [value] for your pipe...

Note, this pipe is rather only for showing the desired output in the view.

<form [formGroup]="myForm">
  <input 
    [value]="myForm.get('amount').value | udpCurrency"
    formControlName="amount" 
    placeholder="Amount">
</form>

How to use pipes in Angular 5 reactive form input - angular - html, EDIT: To add to my answer above, you can use a pipe: import {Pipe, PipeTransform} from '#angular/core'; #Pipe({ name: 'maxLength' }) export class MaxLength implements PipeTransform { transform(value: string): string { if (value) { return value. Angular provides two different approaches to handling user input through forms: reactive and template-driven. Both capture user input events from the view, validate the user input, create a form model and data model to update, and provide a way to track changes.

I thought I had this working but as it turns out, I was wrong (and accepted a wrong answer). I just redid my logic in a new way that works better for me and answers the concern of Jacob Roberts in the comments above. Here is my new solution:

The Template:

<form [formGroup]="myForm">
  <input formControlName="amount" placeholder="Amount">
</form>

The Component:

import { Component, OnInit, HostListener } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { UdpCurrencyMaskPipe } from '../../../_helpers/udp-currency-mask.pipe';

export class MyComponent implements OnInit {
  myForm: FormGroup;

  constructor(
    private builder: FormBuilder,
    private currencyMask: UdpCurrencyMaskPipe,
  ) {
    this.myForm = builder.group({
      amount: ['', Validators.required]
    });

    this.myForm.valueChanges.subscribe(val => {
      if (typeof val.amount === 'string') {
        const maskedVal = this.currencyMask.transform(val.amount);
        if (val.amount !== maskedVal) {
          this.myForm.patchValue({amount: maskedVal});
        }
      }
    });
  }    
}

The Pipe:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
    name: 'udpCurrencyMask'
})
export class UdpCurrencyMaskPipe implements PipeTransform {
    amount: any;

    transform(value: any, args?: any): any {

        let amount = String(value);

        const beforePoint = amount.split('.')[0];
        let integers = '';
        if (typeof beforePoint !== 'undefined') {
            integers = beforePoint.replace(/\D+/g, '');
        }
        const afterPoint = amount.split('.')[1];
        let decimals = '';
        if (typeof afterPoint !== 'undefined') {
            decimals = afterPoint.replace(/\D+/g, '');
        }
        if (decimals.length > 2) {
            decimals = decimals.slice(0, 2);
        }
        amount = integers;
        if (typeof afterPoint === 'string') {
            amount += '.';
        }
        if (decimals.length > 0) {
            amount += decimals;
        }

        return amount;
    }
}

Now there are several things i learned here. One was what that what Jacob said was true, the other way only worked initially but would not update when the value had changed. Another very important thing to note was that I need a completely different type of pipe for a mask as compared to a view pipe. For example, a pipe in a view might take this value "100" and convert it to "$100.00" however you would not want that conversion to happen as you are typing the value, you would only want that to happen after were done typing. For this reason i created my currency mask pipe which simply removes non numeric numbers and restricts the decimal to two places.

How to use pipes in Angular 5 reactive form input, This is what can happen when you mix template driven form and reactive form. You have two bindings fighting each other. Choose either  There are two different approaches to forms in Angular. The first category are the template-driven forms. Using this method, you first create html-input-elements and then use directives like ngModel to bind their value to a component's variable. Personally, I've used this technique a lot.

I was going to write a custom control, but found that overriding the "onChange" from the FormControl class via ngModelChange was easier. The emitViewToModelChange: false is critical during your update logic to avoid recurring loop of change events. All piping to currency happens in the component and you don't have to worry about getting console errors.

<input matInput placeholder="Amount" 
  (ngModelChange)="onChange($event)" formControlName="amount" />
@Component({
  providers: [CurrencyPipe]
})
export class MyComponent {
  form = new FormGroup({
    amount: new FormControl('', { validators: Validators.required, updateOn: 'blur' })
  });

  constructor(private currPipe:CurrencyPipe) {}

  onChange(value:string) {
    const ctrl = this.form.get('amount') as FormControl;

    if(isNaN(<any>value.charAt(0))) {
      const val = coerceNumberProperty(value.slice(1, value.length));
      ctrl.setValue(this.currPipe.transform(val), { emitEvent: false, emitViewToModelChange: false });
    } else {
      ctrl.setValue(this.currPipe.transform(value), { emitEvent: false, emitViewToModelChange: false });
    }
  }

  onSubmit() {
    const rawValue = this.form.get('amount').value;

    // if you need to strip the '$' from your input's value when you save data
    const value = rawValue.slice(1, rawValue.length);

    // do whatever you need to with your value
  }
}

Pipes in reactive forms. how to ? : Angular2, Every tutorial out there don't include pipes in reactive forms, and that's include A CamelCase pipe for example, that transform the input to be CamelCased. 5 days ago A declarative library for handling hotkeys in Angular applications. In order to understand how the ngIf as syntax is an important part of the Angular built-in reactive programming support, we will need a more concrete example where we will load some data from the backend. We will then try to display the data on the screen using the async pipe.

Without knowing your pipe code, it's likely throwing errors because of where you're constructing that form.

Try using Angular's change detection hooks to set that value after inputs have been resolved:

export class MyComponent implements OnInit {
  myForm: FormGroup;

  constructor(private builder: FormBuilder) { }    

  ngOnInit() {
    this.myForm = builder.group({
      amount: ['', Validators.required]
    });
  }

}

5 usage ideas for Angular pipes, v2 onwards. But it has evolved over the period of time. then using modeltxt in pipe. using modeltxt.value in the pipe. if I had code text in the pipe the pipe works I also tried . ngOnInit() { this.prodForm.valueChanges.subscribe(v => this.modelValue = v.model); } then used {{modelValue}} in the pipe The code works with template forms I just need to know how to format and get the value to insert it in the pipe. this is one of the pipes

The other answers here didn't work properly for me but I found a way that works very well. You need to apply the pipe transform inside the reactive form valueChanges subscription, but don't emit the event so it doesn't create a recursive loop:

this.formGroup.valueChanges.subscribe(form => {
  if (form.amount) {
    this.formGroup.patchValue({
      amount: this.currencyMask.transform(form.amount)
    }, {
      emitEvent: false
    });
  }
});

This also requires that your pipe "unformats" whatever was there, which is usually as simply as something like this inside your pipe's transform function:

value = value.replace(/\$+/g, '');

Pipes In Angular 5, Reactive forms - uppercase reverse pipe #48033222. Validators } from '@​angular/forms'; name: String = 'Angular 5';. myForm: listen to input changes. There are three steps to using form controls. Register the reactive forms module in your app. This module declares the reactive-form directives that you need to use reactive forms. Generate a new FormControl instance and save it in the component. Register the FormControl in the template.

An Introductory Guide to Angular Reactive Forms, This is a complex angular 8 reactive forms guide with the example on stackblitz.​com. with form array; How to use currency pipe in HTML and in component 5. Listen to form value changes. // we could simpli subcribe to our  Introducing Angular pipes, a way to write display-value transformations that you can declare in your HTML. Using pipeslink. A pipe takes in data as input and transforms it to a desired output. In this page, you'll use pipes to transform a component's birthday property into a human-friendly date.

Angular 2 FormControl Example, Introducing Angular pipes, a way to write display-value transformations that you can declare in your HTML. Using pipeslink. A pipe takes in data as input and  You would likely create something similar (e.g. adapt template etc. to other form input types) but replace the conversion functions with your desired Pipe transform methods (probably two different types) to achieve what you are after. Angular documentation or source code could be helpful for further details.

uppercase-reactive-pipe, Pipes. Forms. Introduction · Reactive Forms · Template-driven Forms Syncs a FormControl in an existing FormGroup to a form control element by name. Triggers a warning that this input should not be used with reactive forms. Support for using the ngModel input property and ngModelChange event with reactive form  Angular makes no use of the container, form-group, form-control, and btn classes or the styles of any external library. Angular apps can use any CSS library or none at all. Angular apps can use any CSS library or none at all.

Comments
  • is the expression error coming from the pipe or the component?
  • The component html. specifically the line that has this "[ngModel]="f1.value.amount | udpCurrency"
  • This was extremely helpful thanks. I found a bunch of posts on this subject that were all overly complex but this just works.
  • this works initially but when you edit the value, the pipe doesn't reapply onblur. Is this something that has to be handled explicitly?
  • @JacobRoberts Sorry, i didn't see your comment there for a few months. I finally realized what you were saying and you are correct. I have a new answer below that might help if you are still having the same issue.
  • This doesn't work as expected because the form value change fires before the pipe transform. The displayed value will look right but the form value will be different.
  • This doesn't work, because after the form updates the model on the view, the currency pipe again updates the model and ends up trying to pipe a string value which is where I was getting the error. Check out my solution below to avoid this.
  • My form building was happening in the constructor, however it depended on other data retrieved from an http request so even though it was not in the ngOnInit hook i believe it was called after ngOnInit. as a test i moved the building to within ngOnInit and I still ge the error

Hot Questions

  • Build apk failed with error: package android.arch.core.util does not exist2388
  • How do I make a text file appear to type itself using a batch file?2952
  • how to write a function that takes 2 strings, and add them to the BEGINNING of the respective arrays8420
  • Disable download/print button in primefaces documentViewer4279
  • How to Write Int Mid Function in C#6591
  • Regex replace all character except last 5 character and whitespace with plus sign1354
  • SQLSTATE[HY000] [1045] Access denied for user 'username'@'localhost' using CakePHP5498
  • Angular 7 rxjs/forkJoin : You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable9393
  • How to count the number of underscores and split the string on the middle one only?7654
  • Multiline editable text UITextview inside UIAlertController?1431
  • Is it possible to tell ansible not to use ~/.ssh/config?3488
  • export is not recognize in cmd while Cygwin is installed647
  • UnAuthorized issue when request user list to Microsoft Graph by using HttpClient3811
  • Can't have multiple template bindings on one element. OR statement1947
  • list.reverse does not return list?7391
  • What is the command to invoke RStudio from Command Line in linux environment?1026
  • What is a good way to round double-precision values to a (somewhat) lower precision?8578
  • How to find the parameter key from window location path?6912
  • MYSQL: How to JOIN two tables on the same query referencing the same table twice6415
  • Eclipe LUNA - "The import java.sql cannot be resolved"8232