I have an editform using an editcontext:
<EditForm OnValidSubmit="HandleValidSubmit" EditContext="_editContext" Context="auth">
<DataAnnotationsValidator />
<input type="time" @bind-value="_foodTruck.EndDelivery" @onkeydown="@(q=>ResetValidation("EndDelivery"))" >
<ValidationMessage For="() => _foodTruck.EndDelivery" />
<input type="time" @bind-value="_foodTruck.StartDelivery" @onkeydown="@(q=>ResetValidation("StartDelivery"))" >
<ValidationMessage For="() => _foodTruck.StartDelivery" />
<input class="btn btn-default" type="submit" value="save" />
</EditForm>
I do some custom validations in HandleValidSubmit:
EditContext _editContext = new EditContext(_foodTruck);
private async void HandleValidSubmit()
{
var messageStore = new ValidationMessageStore(_editContext);
if (_foodTruck.StartDelivery >= _foodTruck.EndDelivery)
{
messageStore.Add(_editContext.Field("EndDelivery"), "Bad time entered");
_editContext.NotifyValidationStateChanged();
}
if (!_editContext.Validate()) return;
}
What now happens is that my custom error ("bad time entered") is displayed at the right position. The only issue is: That error does not disappear when I change the value. So HandleValidSubmit is never called again if I click onto the submit button.
I also tried emptying the validationerrors when modifying the fields:
protected void ResetValidation(string field)
{
var messageStore = new ValidationMessageStore(_editContext);
messageStore.Clear(_editContext.Field(field));
messageStore.Clear();
_editContext.NotifyValidationStateChanged();
}
This is called by onkeydown
. But that doesn't seem to have an effect, either. The Errormessage does not disappear and so HandleValidSubmit
isn't called either.
I solved this by creating a new EditContext on Validation-reset. So I simply added the following line to the ResetValidation-Method:
_editContext = new EditContext(_foodTruck);
But to be honest: That does not feel right. So I will leave this open for better answers to come (hopefully).
I had the same issue as the original poster so I decided to poke around in the source code of the EditContext (thank you source.dot.net!). As a result, I've come up with a work-around that should suffice until the Blazor team resolves the issue properly in a future release.
/// <summary>
/// Contains extension methods for working with the <see cref="EditForm"/> class.
/// </summary>
public static class EditFormExtensions
{
/// <summary>
/// Clears all validation messages from the <see cref="EditContext"/> of the given <see cref="EditForm"/>.
/// </summary>
/// <param name="editForm">The <see cref="EditForm"/> to use.</param>
/// <param name="revalidate">
/// Specifies whether the <see cref="EditContext"/> of the given <see cref="EditForm"/> should revalidate after all validation messages have been cleared.
/// </param>
/// <param name="markAsUnmodified">
/// Specifies whether the <see cref="EditContext"/> of the given <see cref="EditForm"/> should be marked as unmodified.
/// This will affect the assignment of css classes to a form's input controls in Blazor.
/// </param>
/// <remarks>
/// This extension method should be on EditContext, but EditForm is being used until the fix for issue
/// <see href="https://github.com/dotnet/aspnetcore/issues/12238"/> is officially released.
/// </remarks>
public static void ClearValidationMessages(this EditForm editForm, bool revalidate = false, bool markAsUnmodified = false)
{
var bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
object GetInstanceField(Type type, object instance, string fieldName)
{
var fieldInfo = type.GetField(fieldName, bindingFlags);
return fieldInfo.GetValue(instance);
}
var editContext = editForm.EditContext == null
? GetInstanceField(typeof(EditForm), editForm, "_fixedEditContext") as EditContext
: editForm.EditContext;
var fieldStates = GetInstanceField(typeof(EditContext), editContext, "_fieldStates");
var clearMethodInfo = typeof(HashSet<ValidationMessageStore>).GetMethod("Clear", bindingFlags);
foreach (DictionaryEntry kv in (IDictionary)fieldStates)
{
var messageStores = GetInstanceField(kv.Value.GetType(), kv.Value, "_validationMessageStores");
clearMethodInfo.Invoke(messageStores, null);
}
if (markAsUnmodified)
editContext.MarkAsUnmodified();
if (revalidate)
editContext.Validate();
}
}
Add this.StateHasChanged() at the end of the event action so that it can render the ui elements again and remove the validation message.
EditContext _editContext = new EditContext(_foodTruck);
private async void HandleValidSubmit()
{
var messageStore = new ValidationMessageStore(_editContext);
if (_foodTruck.StartDelivery >= _foodTruck.EndDelivery)
{
messageStore.Add(_editContext.Field("EndDelivery"), "Bad time entered");
_editContext.NotifyValidationStateChanged();
this.StateHasChanged(); //this line
}
if (!_editContext.Validate()) return;
}
for the other one
protected void ResetValidation(string field)
{
var messageStore = new ValidationMessageStore(_editContext);
messageStore.Clear(_editContext.Field(field));
messageStore.Clear();
_editContext.NotifyValidationStateChanged();
this.StateHasChanged(); //this line
}
kindly let me know if it works
I had same problem. I couldn't find straightforward solution. Workaround similar to below worked for me.
Modify EditForm as follows -
<EditForm EditContext="_editContext" OnSubmit="HandleSubmit">
@Code Block
EditContext _editContext;
ValidationMessageStore msgStore;
FoodTruck _foodTruck= new FoodTruck();
protected override void OnInitialized()
{
_editContext = new EditContext(_foodTruck);
msgStore = new ValidationMessageStore(_editContext);
}
void HandleSubmit()
{
msgStore.Clear();
if(_editContext.Validate()) // <-- Model Validation
{
if (_foodTruck.StartDelivery >= _foodTruck.EndDelivery) //<--Custom validation
{
msgStore = new ValidationMessageStore(_editContext);
msgStore.Add(_editContext.Field("EndDelivery"), "Bad time entered");
}
}
}
Had the same issue, solved it in a not-too-hacky way using EditContext.Validate()
:
I have already implemented a method called EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
which gets called as soon that a parameter of the model used by the EditForm is used. It´s implemented like this:
protected override void OnInitialized()
{
EditContext = new EditContext(ModelExample);
EditContext.OnFieldChanged += EditContext_OnFieldChanged;
}
Here´s the method:
private void EditContext_OnFieldChanged(object sender, FieldChangedEventArgs e)
{
EditContext.Validate();
// ...
// other stuff you want to be done when the model changes
}
EditContext.Validate()
seems to update all validation messages, even the custom ones.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With