Using Pipes within ngModel on INPUT Elements in Angular

AngularPipeHtml InputAngular2 Ngmodel

Angular Problem Overview


I've an HTML INPUT field.

<input 
    [(ngModel)]="item.value" 
    name="inputField" 
    type="text" 
/>

and I want to format its value and use an existing pipe:

.... 
[(ngModel)]="item.value | useMyPipeToFormatThatValue" 
....

and get the error message:

> Cannot have a pipe in an action expression

How can I use pipes in this context?

Angular Solutions


Solution 1 - Angular

You can't use Template expression operators(pipe, save navigator) within template statement:

(ngModelChange)="Template statements"

(ngModelChange)="item.value | useMyPipeToFormatThatValue=$event"

https://angular.io/guide/template-syntax#template-statements

> Like template expressions, template statements use a language that > looks like JavaScript. The template statement parser differs from the > template expression parser and specifically supports both basic > assignment (=) and chaining expressions (with ; or ,). > > However, certain JavaScript syntax is not allowed: > > - new > - increment and decrement operators, ++ and -- > - operator assignment, such as += and -= > - the bitwise operators | and & > - the template expression operators

So you should write it as follows:

<input [ngModel]="item.value | useMyPipeToFormatThatValue" 
      (ngModelChange)="item.value=$event" name="inputField" type="text" />

Plunker Example

Solution 2 - Angular

<input [ngModel]="item.value | useMyPipeToFormatThatValue" 
      (ngModelChange)="item.value=$event" name="inputField" type="text" />

The solution here is to split the binding into a one-way binding and an event binding - which the syntax [(ngModel)] actually encompasses. [] is one-way binding syntax and () is event binding syntax. When used together - [()] Angular recognizes this as shorthand and wires up a two-way binding in the form of a one-way binding and an event binding to a component object value.

The reason you cannot use [()] with a pipe is that pipes work only with one-way bindings. Therefore you must split out the pipe to only operate on the one-way binding and handle the event separately.

See Angular Template Syntax for more info.

Solution 3 - Angular

<input [ngModel]="item.value | currency" (ngModelChange)="item.value=$event"
name="name" type="text" />

I would like to add one more point to the accepted answer.

If the type of your input control is not text the pipe will not work.

Keep it in mind and save your time.

Solution 4 - Angular

I tried the solutions above yet the value that goes to the model were the formatted value then returning and giving me currencyPipe errors. So i had to

  [ngModel]="transfer.amount | currency:'USD':true"
                                   (blur)="addToAmount($event.target.value)"
                                   (keypress)="validateOnlyNumbers($event)"

And on the function of addToAmount -> change on blur cause the ngModelChange was giving me cursor issues.

removeCurrencyPipeFormat(formatedNumber){
    return formatedNumber.replace(/[$,]/g,"")
  }

And removing the other non numeric values.

validateOnlyNumbers(evt) {
  var theEvent = evt || window.event;
  var key = theEvent.keyCode || theEvent.which;
  key = String.fromCharCode( key );
  var regex = /[0-9]|\./;
  if( !regex.test(key) ) {
    theEvent.returnValue = false;
    if(theEvent.preventDefault) theEvent.preventDefault();
  }

Solution 5 - Angular

My Solution is given below here searchDetail is an object..

<p-calendar  [ngModel]="searchDetail.queryDate | date:'MM/dd/yyyy'"  (ngModelChange)="searchDetail.queryDate=$event" [showIcon]="true" required name="queryDate" placeholder="Enter the Query Date"></p-calendar>

<input id="float-input" type="text" size="30" pInputText [ngModel]="searchDetail.systems | json"  (ngModelChange)="searchDetail.systems=$event" required='true' name="systems"
            placeholder="Enter the Systems">

Solution 6 - Angular

you must use [ngModel] instead of two way model binding with [(ngModel)]. then use manual change event with (ngModelChange). this is public rule for all two way input in components.

because pipe on event emitter is wrong.

Solution 7 - Angular

because of two way binding, To prevent error of:

ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was 
checked.

you can call a function to change model like this:

<input 
  [ngModel]="item.value" 
  (ngModelChange)="getNewValue($event)" 
  name="inputField" 
  type="text" 
/>

import { UseMyPipeToFormatThatValuePipe } from './path';

  //...
  constructor(
    private useMyPipeToFormatThatValue: UseMyPipeToFormatThatValuePipe,
  )
  //....
  getNewValue(ev: any): any {
    item.value= this.useMyPipeToFormatThatValue.transform(ev);
  }  

it'll be good if there is a better solution to prevent this error.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLonelyView Question on Stackoverflow
Solution 1 - AngularyurzuiView Answer on Stackoverflow
Solution 2 - AngularKnowHoperView Answer on Stackoverflow
Solution 3 - AngularTibin ThomasView Answer on Stackoverflow
Solution 4 - Angularcabaji99View Answer on Stackoverflow
Solution 5 - AngularBhasker The NavigatorView Answer on Stackoverflow
Solution 6 - Angularhamid_reza hobabView Answer on Stackoverflow
Solution 7 - AngularMohammad Reza MrgView Answer on Stackoverflow