forms: signals - number `[formField]` loses characters while typing (parsed value written back to the input on every keystroke) · Issue #69635 · angular/angular · GitHub
Skip to content

forms: signals - number [formField] loses characters while typing (parsed value written back to the input on every keystroke) #69635

Description

@apimentasoto

Which @angular/* package(s) are the source of the bug?

forms

Is this a regression?

No

Description

Description

When a number | null field is bound to a native <input> via [formField], the input's
displayed text is overwritten with the parsed model value on every keystroke. Intermediate
states that don't round-trip through Number → String (e.g. -0, 1.0000) are lost mid-edit,
so characters disappear while typing.

The same happens with the Angular 22 number | null<input type="text"> binding.

The equivalent reactive-forms setup (FormControl on the same native input) does not show this.

I noticed this on ng 21 when the feature was experimental but I was hoping it would get fixed. I did see some related issues like #67847 and that got addressed, however it seems only targetting CVA controls.

Just the fact that it's not possible to type/input a negative decimal number without going back to add the - (minus) seems like a big inconvenience...

Reproduction

Minimal standalone component:

import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { form, FormField } from '@angular/forms/signals';

@Component({
  selector: 'app-root',
  imports: [FormField],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <input type="number" step="0.01" [formField]="f.numero">
    <input type="text" inputmode="decimal" [formField]="f.numeroTesto">
    <pre>{{ model() | json }}</pre>
  `,
})
export class App {
  model = signal<{ numero: number | null; numeroTesto: number | null }>(
    { numero: null, numeroTesto: null },
  );
  f = form(this.model);
}

Type character-by-character (real keystrokes — not paste, not input.value = …):

# Field Typed keystroke-by-keystroke Expected Actual
A type=number - 0 . 5 -0.5 0.5 (minus dropped)
B type=number 1 . 0 0 0 0 5, then Backspace, then 4 1.00004 14
C type=text - 0 . 5 -0.5 0.5 (minus dropped)

Injecting the whole value in one programmatic InputEvent (e.g. -0.5) keeps it intact — only
incremental typing is affected.

Expected behavior

Typing into the input should not have the parsed value re-rendered back onto it mid-edit;
intermediate states (-, -0, 1.0000) should be preserved while the user types, as with a
reactive FormControl.

Actual behavior

Characters are lost / the value is corrupted while typing (table above). No console errors.

Please provide a link to a minimal reproduction of the bug

https://github.com/apimentasoto/signal-forms-number-repro

Please provide the exception or error you saw


Please provide the environment you discovered this bug in (run ng version)

Angular CLI       : 22.0.5
Angular           : 22.0.5
Node.js           : 24.18.0
Package Manager   : npm 11.16.0
Operating System  : linux x64

┌───────────────────────────┬───────────────────┬───────────────────┐
│ Package                   │ Installed Version │ Requested Version │
├───────────────────────────┼───────────────────┼───────────────────┤
│ @angular/build            │ 22.0.5            │ ^22.0.4           │
│ @angular/cli              │ 22.0.5            │ ^22.0.4           │
│ @angular/common           │ 22.0.5            │ ^22.0.0           │
│ @angular/compiler         │ 22.0.5            │ ^22.0.0           │
│ @angular/compiler-cli     │ 22.0.5            │ ^22.0.0           │
│ @angular/core             │ 22.0.5            │ ^22.0.0           │
│ @angular/forms            │ 22.0.5            │ ^22.0.0           │
│ @angular/platform-browser │ 22.0.5            │ ^22.0.0           │
│ rxjs                      │ 7.8.2             │ ~7.8.0            │
│ typescript                │ 6.0.3             │ ~6.0.2            │
└───────────────────────────┴───────────────────┴───────────────────┘

Anything else?

Minimal reproduction (clone and run — one standalone component, no Angular Material or router):

git clone https://github.com/apimentasoto/signal-forms-number-repro
cd signal-forms-number-repro && npm install && npm start

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions