fix(forms): preserve intermediate number values in signal forms by SkyZeroZx · Pull Request #69637 · angular/angular · GitHub
Skip to content

fix(forms): preserve intermediate number values in signal forms - #69637

Merged
mattrbeck merged 2 commits into
angular:mainfrom
SkyZeroZx:fix/signal-forms-number-input-typing
Jul 15, 2026
Merged

mattrbeck merged 2 commits into
angular:mainfrom
SkyZeroZx:fix/signal-forms-number-input-typing

Conversation

@SkyZeroZx

Copy link
Copy Markdown
Contributor

Preserve raw native input text while editing so parsed model values are not written back on every keystroke.

Fixes #69635.

@pullapprove
pullapprove Bot requested a review from crisbeto July 3, 2026 18:08
@ngbot ngbot Bot added this to the Backlog milestone Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to update this to avoid the mismatch between the input and the model for the specific case of -0, which is found in the added tests

@JeanMeche

Copy link
Copy Markdown
Member

That seems to be an interesting change.
However I noticed it added support for non-decimal formats, eg: 0b0101 => 5, 0x22 => 34.

Not sure if we should consider that a bug or a feature.

@SkyZeroZx

Copy link
Copy Markdown
Contributor Author

That seems to be an interesting change. However I noticed it added support for non-decimal formats, eg: 0b0101 => 5, 0x22 => 34.

Not sure if we should consider that a bug or a feature.

Good catch, that's a good question. According to the HTML standard, we shouldn't allow it, so maybe it's a bug?

@JeanMeche

Copy link
Copy Markdown
Member

Looks like some files are having formatting issues, it will be fixed by #69679

@JeanMeche
JeanMeche removed the request for review from crisbeto July 8, 2026 14:51
@JeanMeche JeanMeche added the action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews label Jul 8, 2026
SkyZeroZx added 2 commits July 8, 2026 16:32
Preserve raw native input text while editing so parsed model values are not written back on every keystroke.

Fixes angular#69635.
@SkyZeroZx
SkyZeroZx force-pushed the fix/signal-forms-number-input-typing branch from 3321b98 to 042e645 Compare July 8, 2026 21:33
@SkyZeroZx
SkyZeroZx requested a review from JeanMeche July 8, 2026 21:33
@JeanMeche JeanMeche added action: merge The PR is ready for merge by the caretaker target: patch This PR is targeted for the next patch release and removed action: cleanup The PR is in need of cleanup, either due to needing a rebase or in response to comments from reviews labels Jul 9, 2026
@mattrbeck
mattrbeck merged commit 2e32872 into angular:main Jul 15, 2026
27 checks passed
@mattrbeck

Copy link
Copy Markdown
Member

This PR was merged into the repository. The changes were merged into the following branches:

(rawValue: unknown) => {
// Mark the parsed value as already seen from this native control so the next update pass
// does not reformat and write it back over the user's in-progress input text.
bindings['controlValue'] = rawValue;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding this line seems to be breaking. I'll need to investigate more.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What kind of problem is this causing? Would there be a minimal reproduction example to validate it?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here would be one

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

@Component({
  selector: 'app-root',
  imports: [FormField],
  template: `
    <input [formField]="field" placeholder="Type 'hello ' with a space" />
    <p>Local Signal (Input Buffer): "{{ text() }}"</p>
    <p>Normalized Model (Trimmed): "{{ model() }}"</p>
  `,
})
export class App {
  // 1. Local signal bound to the input
  text = signal<string>('');

  // 2. The FormField directive from @angular/forms/signals
  field = form(this.text);

  // 3. The "normalized" model or external state
  model = signal<string>('');

  constructor() {
    // Effect A: Sync Local -> Model (Trimming)
    // When the user types, trim the input and update the model.
    effect(() => {
      const currentText = this.text();
      const trimmed = currentText.trim();

      if (this.model() !== trimmed) {
        this.model.set(trimmed);
      }
    });

    // Effect B: Sync Model -> Local
    // DEPENDENCY TRAP: This effect reads 'text()', meaning it runs on every keystroke.
    effect(() => {
      const currentModel = this.model();

      // Reading this.text() makes this effect dependent on the 'text' signal.
      if (this.text() !== currentModel) {
        // --- 🔴 THE REGRESSION POINT ---
        // In the culprit Angular version, calling text.set() here eagerly
        // overwrote the DOM buffer, swallowing the space the user just typed.
        this.text.set(currentModel);
      }
    });
  }
}

@angular-automatic-lock-bot

Copy link
Copy Markdown

@angular-automatic-lock-bot angular-automatic-lock-bot Bot locked and limited conversation to collaborators Aug 16, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

action: merge The PR is ready for merge by the caretaker area: forms target: patch This PR is targeted for the next patch release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

3 participants