-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
Is there an existing issue for this?
- I have searched the existing issues
Is your feature request related to a problem? Please describe the problem.
Description
When using Blazor WASM form validation with complex nested objects that may replace instances at runtime,
inputs derived from InputBase<TValue> can display stale UI and validation state.
InputBase.SetParametersAsync assigns its FieldIdentifier only once on initialization. If the underlying FieldIdentifier.Model object instance changes, the component keeps using the old (Model, FieldName) pair. As a result, EditContext.GetValidationMessages() may return an empty set,
but the input remains visually invalid because its cached FieldIdentifier still points to the previous instance.
Reproduction example
Let's say we have a checkout form where user has to enter amount and select a payment method.
Models would look like this.
public class CheckoutForm
{
public PaymentMethod Payment { get; set; }
}
public abstract class PaymentMethod
{
[Required]
[Range(1, 999, ErrorMessage = "Amount must be between 1 and 999.")]
public int Amount { get; set; }
}
public class CardPayment : PaymentMethod
{
// whatever fields for card payment
}
public class PayPalPayment : PaymentMethod
{
// whatever fields for paypal payment
}
And a code that performs payment method change:
private void HandlePaymentMethodChange(PaymentType type) {
if (type == PaymentType.Card) {
FormModel.Payment = new CardPayment {
Amount = FormModel.Payment.Amount
}
}
if (type == PaymentType.PayPal) {
FormModel.Payment = new PayPalPayment {
Amount = FormModel.Payment.Amount
}
}
}
Steps to reproduce:
- Enter an invalid value in Amount (e.g., value less than 1 or more than 999).
- Switch from
CardPaymenttoPayPalPaymentthe Payment property reference changes). - Enter a valid numeric value.
Expected
The input should reflect the new, valid state of the new Payment instance.
Actual
The EditContext has no validation messages, but the input still displays as invalid.
The old FieldIdentifier is still used by the input component.
Current workaround
Usage of key attribute with a value of model instance resolves issue because each time model is changed, the subtree is fully re-created leading to re-initialization of FieldIdentifiers.
<EditContext>
<PaymentMethodComponent @key="@FormModel.Payment" />
</EdiContext>
Describe the solution you'd like
The solution would be to update InputBase.SetParametersAsync code by providing additional check for reference equality between previous FieldIdentifier.Model and current one.
public override Task SetParametersAsync(ParameterView parameters)
{
// ... old code
// NEW: detect instance swap for the owner of ValueExpression's final member
if (ValueExpression is not null)
{
var newField = FieldIdentifier.Create(ValueExpression);
// If the owning instance or the field changed, switch identifiers
if (!ReferenceEquals(newField.Model, FieldIdentifier.Model))
{
// Clear parsing messages we (this input) may have added for the OLD field
if (_parsingValidationMessages is not null)
{
_parsingValidationMessages.Clear(FieldIdentifier);
EditContext?.NotifyValidationStateChanged();
}
// Switch to NEW field
FieldIdentifier = newField;
// Reset parsing/display state so we don't carry stale UI forward
_parsingFailed = false;
_previousParsingAttemptFailed = false;
_incomingValueBeforeParsing = null;
}
}
}
Additional context
No response