Skip to content

Preserve modified state when InputBase parsing fails - #68365

Open
PureWeen wants to merge 3 commits into
dotnet:mainfrom
PureWeen:pureween-fix-inputbase-parse-notification
Open

Preserve modified state when InputBase parsing fails#68365
PureWeen wants to merge 3 commits into
dotnet:mainfrom
PureWeen:pureween-fix-inputbase-parse-notification

Conversation

@PureWeen

@PureWeen PureWeen commented Aug 11, 2026

Copy link
Copy Markdown
Member

Fix InputBase parse failures without reporting a model value change

Description

When TryParseValueFromString fails, the raw value in the input changed but the bound model value did not. The existing parse-failure path calls EditContext.NotifyFieldChanged, which does two things:

  1. Marks the field modified.
  2. Raises OnFieldChanged, causing validators to run against the unchanged model value.

That can produce both the parsing error and an unrelated model-validation error, such as [Required], even though CurrentValue, ValueChanged, and the model were not updated.

This change separates those two effects. A parse failure still marks the field modified, preserving the existing dirty-state and CSS behavior, but it no longer raises OnFieldChanged. Parsing messages continue through the existing NotifyValidationStateChanged flow.

Fixes #58407

Design

EditContext.NotifyFieldChanged now delegates its state mutation to a new public MarkAsModified method before raising OnFieldChanged. InputBase calls only MarkAsModified when parsing fails.

The API is symmetric with MarkAsUnmodified(in FieldIdentifier) and gives custom input implementations a supported way to record user interaction without claiming that the bound model value changed. Forms and Web are separate assemblies, and framework code should not bridge that boundary with InternalsVisibleTo or UnsafeAccessor, so the public API is the explicit contract between them.

Areas I would especially like reviewed

  1. Modified-state contract: Is a user-entered but unparseable value still considered modified? This PR preserves the existing modified invalid behavior while suppressing only the value-change notification.
  2. Public API shape: Is EditContext.MarkAsModified(in FieldIdentifier) the right symmetric counterpart to MarkAsUnmodified for this scenario?
  3. Notification boundary: The first valid value after a failed parse must resume the normal ValueChanged and OnFieldChanged path exactly once.
  4. Opposite boundary: Empty input for nullable values remains a successful model change and still runs normal [Required] validation.

Alternative PR

#65574 addresses the same issue by removing NotifyFieldChanged from the parse-failure branch. That is much smaller, but it also changes EditContext.IsModified(field) from true to false after invalid user input.

This PR keeps the useful part of the existing behavior, namely modified-state tracking, while removing only the model-value-change notification. The main product decision between these PRs is whether failed input should remain modified, not whether the extra model validation should be suppressed.

Tests

  • InputBaseTest: 24/24 passed.
  • EditContextTest and EditContextDataAnnotationsExtensionsTest: 43/43 passed.
  • Browser E2E: Server and WebAssembly cases passed 2/2.
  • The regression assertion fails against the pre-fix source with one unexpected OnFieldChanged event and passes with this change.
  • Published Release-trimmed WebAssembly and Release-trimmed WebAssembly AOT both passed the initial-invalid, valid, valid-to-invalid, and empty-input browser transitions with no console, page, or network failures.
  • After the public API rework, the complete Forms and Web test projects build and pass with zero warnings or errors.

Copilot AI added 2 commits August 11, 2026 15:01
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 0fb5ea3b-44bb-495b-99c5-93e753ca9ce1
Keep the mark-only EditContext operation internal and bridge it from InputBase without raising OnFieldChanged or expanding public API surface. Strengthen repeated-invalid, recovery, model-preservation, and browser coverage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: f88407e7-efcf-44b1-9387-cde2a2557973
Copilot AI lite review requested due to automatic review settings August 11, 2026 20:07
@PureWeen
PureWeen requested a review from a team as a code owner August 11, 2026 20:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This pull request adjusts Blazor Forms’ handling of InputBase parse failures so that invalid user input still marks the field as modified (preserving “dirty”/CSS behavior) but does not raise EditContext.OnFieldChanged, avoiding validators running against an unchanged model value (fixing #58407).

Changes:

  • Refactors EditContext.NotifyFieldChanged to delegate modified-state mutation to a new internal MarkAsModified helper.
  • Updates InputBase’s parse-failure path to mark the field modified without triggering OnFieldChanged, while continuing to notify validation-state changes for parsing messages.
  • Adds unit and E2E coverage for the notification boundary (invalid → valid, valid → invalid, and empty input for nullable required scenarios).
Show a summary per file
File Description
src/Components/Forms/src/EditContext.cs Introduces internal MarkAsModified and refactors NotifyFieldChanged to use it before raising OnFieldChanged.
src/Components/Web/src/Forms/EditContextAccessor.cs Adds a narrow UnsafeAccessor bridge so Web can invoke EditContext.MarkAsModified without making it public.
src/Components/Web/src/Forms/InputBase.cs Uses MarkAsModified (via accessor) on parse failure to avoid revalidating unchanged model values.
src/Components/Forms/test/EditContextTest.cs Adds a unit test verifying MarkAsModified updates modified state without raising OnFieldChanged.
src/Components/Forms/test/EditContextDataAnnotationsExtensionsTest.cs Adds a unit test verifying MarkAsModified does not trigger per-property validation.
src/Components/Web/test/Forms/InputBaseTest.cs Expands/introduces unit tests asserting parse failures don’t raise OnFieldChanged and that subsequent valid input resumes normal behavior.
src/Components/test/testassets/BasicTestApp/FormsTest/TypicalValidationComponent.razor Adds a required nullable number field to support the regression E2E scenario.
src/Components/test/E2ETest/Tests/FormsTest.cs Adds E2E regression test ensuring parse failures don’t trigger model validation while preserving modified/invalid UI state.

Review details

Tip

Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 8/8 changed files
  • Comments generated: 0
  • Review effort level: Lite

Comment thread src/Components/Web/src/Forms/EditContextAccessor.cs Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: f88407e7-efcf-44b1-9387-cde2a2557973
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Blazor] InputBase - failed parsing (eg. InputNumber) triggers field validation

4 participants