htmlangularforms

NgModel does not emit decimals?


I am working on a project where users are expecting to enter numbers in where decimals matter. If the user enters 1.000 we expect to persist 1.000. We use Angular and and leverage template-driven forms. What we discovered is that NgModel does not emit the full number - it always truncates. So even though a user entered 1.000, only 1 is emitted. If a user enters 1.0001 we see the correct value.

What's curious is that if we subscribe to the change or keyup events on the input element, we see the expected value.

Why does ngModelChange emit a different value than keyup or change? Is there a way to get Angular to emit the expected value?

I've put together a simple example in this stackblitz

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [FormsModule],
  template: `
    <h3>Enter a value like "1.000"</h3>
    <!-- you can replace "keyup" with "change" and get the same problem -->
    <input type="number" [(ngModel)]="value" (ngModelChange)="onNgChange($event)" (keyup)="onJSChange($event)">

    <br><br><br>
    <span>From NgModel:</span>
    <div>{{fromNgModel}}</div>

    <span>From Change:</span>
    <div>{{fromChange}}</div>
  `,
})
export class App {
  name = 'Angular';
  value?: number = null;

  fromNgModel: any = null;
  fromChange: any = null;

  onNgChange(evt: any) {
    //typing or copy/pasting "1.000" into the input will yield "1"
    this.fromNgModel = evt?.toString();
  }

  onJSChange(evt: any) {
    //typing or copy/pasting "1.000" into the input will yield "1.000"
    this.fromChange = evt?.target?.value.toString();
  }
}

Solution

  • 1.000 and 1 are the same in JavaScript. If you open your Chrome console and type "1.000", it will print "1".

    The number type does not keep track of extra 0's.

    When you want to present the number with 3 decimal points, use the Angular number pipe:

    valueVariable | number:'0.3-3'

    For a form field, you may need to split the ngModel input and output. Typically you can use [(ngModel)] to update both directions, but here you need to separate them because you need a different value for input and output.

    [ngModel]="valueVariable | number:'0.3-3' " (ngModelChange)="handleValueChange($event)"

    Set valueVariable in your handleValueChange, and that should do it.

    As far as why standard HTML events (change, keyup) retain the extra zeros - they are emitting string values. Strings remember, numbers forget.