I have a EditForm in a Blazor Server application and i want to check if an InputText value is in a list. How can i pass the list to compare from my UI to the Validator class for comparison?
I have tried comparing the @bind-Value in line and encapsulating the validation message but it skips over the validation message when the encapsulating function tests true.
<EditForm Model="@resourceToBeCreated">
<FluentValidationValidator ValidatorType=typeof(ResourceValidator)/>
@if (resourcesSortedCollection.FirstOrDefault(x => x.Name == resourceToBeCreated.Name) != null)
{
<CustomValidationMessage For="() => resourceToBeCreated.Name" />
}
<InputTextOnInput @bind-Value="@resourceToBeCreated.Name" placeholder="Name..." />
</EditForm>
I can obviously do this or something similar in the @code section but i dont get the validation popup on inupt.
So the question is, how can i pass this list to the Validator class for comparison?
EDIT: InputTextOnInput component:
@inherits InputText
<input @attributes="AdditionalAttributes"
value="@CurrentValue"
@oninput="EventCallback.Factory.CreateBinder<string>(this, __value => CurrentValueAsString = __value, CurrentValueAsString)" />
CodePudding user response:
First an inherited InputText
control. This overrides TryParseValueFromString
and does the validation there.
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using System.Diagnostics.CodeAnalysis;
namespace BlazorApp1.Pages;
public class InputTextValidated : InputText
{
[Parameter, EditorRequired] public IEnumerable<string>? CheckList { get; set; }
{ get; set; }
protected override bool TryParseValueFromString(string? value, out string? result, [NotNullWhen(false)] out string? validationErrorMessage)
{
result = null;
validationErrorMessage = null;
var isValid = this.CheckList is not null
&& this.CheckList.Any(item => item.Equals(value, StringComparison.InvariantCultureIgnoreCase));
if (isValid)
result = value;
else
validationErrorMessage = "You must enter a value in the validation list";
return isValid;
}
}
And a test page:
@page "/"
<PageTitle>Index</PageTitle>
<EditForm Model=this.model>
<DataAnnotationsValidator />
<InputTextValidated CheckList=Countries @bind-Value="@this.model.Country" />
<ValidationSummary />
</EditForm>
<div>
Country : @model.Country
</div>
@code {
private DataModel model = new DataModel();
private List<string> Countries = new List<string> { "UK", "Spain" };
public class DataModel
{
public string? Country;
}
}
As an alternative you could use/build an Input List control.
How Validation works
Validation data is held in ValidationMessageStore
's associated with an EditContext
. A ValidationMessageStore
is a composite collection of key/value pairs:
- the field defined as a
FieldIdentifier
[the model as anobject
and the field name as astring
] - the validation message as
string
.
Each validation provider has it's own message store and can clear and add messages to it. It only has write/delete access to it's own message store. Providers get the EditContext
cascaded by the EditForm
, create a message store associated with the EditContext
and logs messages to and clears messages from that store. FluentValidationValidator
, DataAnnotationsValidator
, any InputBase
control or classes you write that interact with the EditContext
are providers with message stores associated with the EditContext
.
ValidationSummary
and ValidationMessage
are consumers. They interact with the message stores associated with a EditContext via the cascaded EditContext
. All the messages are available as read only. ValidationMessage
constructs a FieldIdentifier
from the For
expression to filter the messages.