asp.netvalidationblazor-editform

Using EditForm (Blazor ASP .NET) Validation to ensure duplicate inputs aren't created in Database


I'm creating an application in which a Project is created. The project name I have set out as an EditForm, with the name having a [Required] and a [StringLength] attribute. I'm trying to use the EditForm to run validation, and check that the name of the project doesn't match with one that already exists in the database.

Is this possible to do using EditForm? Or do I need to write a JQuery or something else?

Thanks.


Solution

  • Yes, but you can't easily use a custom attribute because you can't supply the list of existing projects to the attribute at runtime.

    You can either:

    Here's how to build it into a component.

    First our data service to get the projects from the database:

    namespace SO73539843.Data;
    
    public class ProjectService
    {
        public IEnumerable<String> Projects { get; private set; } = Enumerable.Empty<string>();
    
        public async ValueTask GetProjects()
        {
            // emulate a async Db get
            await Task.Delay(100);
            Projects = new List<string> { "UK", "France", "Portugal" };
        }
    }
    

    Registered as follows:

    // Add services to the container.
    builder.Services.AddRazorPages();
    builder.Services.AddServerSideBlazor();
    builder.Services.AddSingleton<WeatherForecastService>();
    builder.Services.AddSingleton<ProjectService>();
    

    Now the component which inherits from InputText. We just override TryParseValueFromString and do our constraint checking there.

    using Microsoft.AspNetCore.Components;
    using Microsoft.AspNetCore.Components.Forms;
    using System.Diagnostics.CodeAnalysis;
    
    namespace SO73539843.Pages
    {
        public class InputProject : InputText
        {
            [Parameter] public IEnumerable<string> Projects { get; set; } = Enumerable.Empty<string>();
    
            protected override bool TryParseValueFromString(string? value, out string? result, [NotNullWhen(false)] out string? validationErrorMessage)
            {
                validationErrorMessage = null;
    
                if (Projects.Any(item => item.Equals(value, StringComparison.CurrentCultureIgnoreCase)))
                    validationErrorMessage = $"The {value} project already exists";
    
                result = value;
    
                return validationErrorMessage == null;
            }
        }
    }
    

    And our test page:

    @page "/"
    @inject ProjectService projectService
    <PageTitle>Index</PageTitle>
    
    <h1>Hello, world!</h1>
    
    <EditForm Model=this.model OnInvalidSubmit=InValid OnValidSubmit=Valid >
        <InputProject @bind-Value=this.model.Value Projects=this.projectService.Projects />
        <button type="submit">Add</button>
        <ValidationSummary />
    </EditForm>
    
    <div class="m-2 p-2 bg-dark text-white">
        Value : @this.model.Value
    </div>
    
    <div class="m-2 p-2 bg-primary text-white">
        Submit : @this.Validation
    </div>
    
    @code {
        private ModelData model = new ModelData();
        private string Validation = "None";
    
        protected async override Task OnInitializedAsync()
            => await this.projectService.GetProjects();
    
        private void Valid()
            => Validation = "Valid";
    
        private void InValid()
            => Validation = "Invalid";
    
        public class ModelData
        {
            public string? Value { get; set; }
        }
    }
    

    enter image description here