14

I want to write some number into <input> and dynamically display it as a decimal inside {{}} through pipe. It throws exception instead. Here's my code:

app.template.html:

<h1>amount = {{amount|number:'1.2-2'}}</h1>
<input [(ngModel)]="amount"/>

app.component.ts:

import {Component} from '@angular/core';
@Component({
  selector: 'my-app',
  templateUrl: 'app/app.template.html'
})
export class AppComponent {
  private amount:number;
}

Plunker: http://plnkr.co/edit/I7ynnwBX4DWJfHNPIPRu?p=preview

Write any number into the input and see exception being thrown in the console.


Edit:

Working code as per rinukkusu suggestion:

app.template.html:

<h1>amount = {{amount|number:'1.2-2'}}</h1>
<input [ngModel]="amount" (ngModelChange)="onChange($event)"/>

app.component.ts:

import { Component } from '@angular/core';
@Component({
  selector: 'my-app',
  templateUrl: 'app/app.template.html'
})
export class AppComponent {
  private amount:number;

  onChange($event) {
    this.amount = +$event;
  }
}

This + next to $event is very important and what makes conversion from string to number possible!

Celebes
  • 1,371
  • 1
  • 12
  • 21

2 Answers2

19

Looking at the source code of Angular 2 I found this:

if (!isNumber(value)) {
  throw new InvalidPipeArgumentException(pipe, value);
}

which means, you actually need to pass a variable of type number. Using the input and binding to ngModel like you did there, your amount variable will always be of type string.

Remember: type hints are only visible in TypeScript. After transpiling to JavaScript you lose that information

I'd suggest implementing a new pipe which converts your variable to a number on the fly:

@Pipe({
    name: 'toNumber'
})
export class ToNumberPipe implements PipeTransform {
    transform(value: string):any {
        let retNumber = Number(value);
        return isNaN(retNumber) ? 0 : retNumber;
    }
}

You can use it like this:

<h1>amount = {{amount | toNumber | number:'1.2-2'}}</h1>
<input [(ngModel)]="amount" />
Maximilian Riegler
  • 22,720
  • 4
  • 62
  • 71
  • 3
    Have you tried it? AFAIR `+xxx` (unary plus) doesn't work in templates, only in code. – Günter Zöchbauer Jul 19 '16 at 14:33
  • Actually no - I assumed them to work haha. I will try and edit my answer, if they don't work! – Maximilian Riegler Jul 19 '16 at 14:34
  • 2
    Okay, so it doesn't work, like @GünterZöchbauer said. I updated my answer with a new approach, which fits better than mangling with the bound variable, because if you change the bound variable on change, the input also changes, which is confusing for the user. – Maximilian Riegler Jul 19 '16 at 14:52
-1

Following rinukkusu's solution above -- I was able to do it without creating a custompipe. I just used <input [(ngModel)]="Number(amount)|number:'1.2-2'"/> and it worked for me.