Search code examples
validationrazorblazor

Display validation error message - compare one input against another


Entered Max value must be greater than Min. Right now my code displays error message when Max is same as Min (using compare). Is there validator that can be used to compare one input against another?

MyData.cs:

 public class MyData
{
    [Required]
    public double Min { get; set; }
    [Compare("Min", ErrorMessage = "checks for matching min value")]
    public double Max { get; set; }
}

Form.razor:

<div class="modal-body">
<EditForm EditContext="@context">
    <DataAnnotationsValidator />
    <label class="form-label" for="Min">Min</label>
    <input class="form-control" @bind=model.Min type="text">
    <label class="form-label" for="Max">Max</label>
    <input class="form-control" @bind=model.Max type="text"> 
    <ValidationMessage For="@(() => model.Max)" />
</EditForm>
</div>

<div class="modal-footer">
<button type="button" class="btn btn-primary" @onclick="() => Done()">Apply</button>
</div>

@code { 
private MyData model = new MyData();
private EditContext context;

protected override void OnInitialized()
{    
    model = (MyData)(modalDialog?.ModalRequest.InData ?? new MyData());
    context = new EditContext(model);
}

private void Done()
{
    if (@model.Max < @model.Min)
    {
    context.Validate();  @*this displays error message*@
    }
    else
    {
        modalDialog?.Close(ModalResult.OK(model));
    }
}

Solution

  • To validate for greater than or less than against another property instead of a value using Data Annotations you require to create a custom validation attribute as shown below:

    GreaterThan attribute

    // Custom attribute for validating greater than other property
    public class GreaterThan : ValidationAttribute
    {
        private readonly string _comparisonProperty;
    
        public GreaterThan(string comparisonProperty)
        {
            _comparisonProperty = comparisonProperty;
        }
        
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            ErrorMessage = ErrorMessageString;
            var currentValue = (double)value; // cast to double same as property type
            
            var property = validationContext.ObjectType.GetProperty(_comparisonProperty);
            if (property == null)
                throw new ArgumentException("Property with this name not found");
    
            var comparisonValue = (double)property.GetValue(validationContext.ObjectInstance); // cast to property type
            
            // comparison condition
            if (currentValue < comparisonValue)
                return new ValidationResult(ErrorMessage);
    
            return ValidationResult.Success;
        }
    }
    

    LessThan attribute
    You can use the same code above to create for LessThan attribute by changing the name and comparison condition to currentValue > comparisonValue.


    Below is an example on how to use Data Annotations to validate your model and display validation errors in the form. It includes GreaterThan custom validation attribute together with other common validation attribute.

    Demo

    Class:

    public class MyData
    {
        [Required]
        [MaxLength(40, ErrorMessage = "Name should be less than 40 characters")]
        [MinLength(4, ErrorMessage ="Name should be more than 4 characters")]
        public string Name { get; set; }
    
        [Required]
        [DataType(DataType.Date)]
        public DateTime? BirthDate { get; set; }
        
        [Required]
        public double Min { get; set; }
        
        [GreaterThan("Min", ErrorMessage = "Max must be greater than Min")]
        public double Max { get; set; }
    
        [Required(ErrorMessage = "Password is required.")]
        public string Password { get; set; }
    
        [Required(ErrorMessage = "Confirmation Password is required.")]
        [Compare("Password", ErrorMessage = "Password and Confirmation Password must match.")]
        public string ConfirmPassword { get; set; }
    }
    

    Razor:
    Note: you can upgrade the styling for your form fields and validation message to your liking.

    @page "/"
    @using BlazorApp1.Models
    
    <EditForm Model="@myData" OnValidSubmit="@HandleValidSubmit">
        <DataAnnotationsValidator/>
        <ValidationSummary/>
    
        <p>
            <label for="Name">Name: </label>
            <InputText id="Name" @bind-Value="myData.Name"/>
            <ValidationMessage For="() => myData.Name"/>
        </p>
        <p>
            <label for="Min">Min: </label>
            <InputNumber id="Min" @bind-Value="myData.Min"/>
            <ValidationMessage For="() => myData.Min"/>
        </p>
        <p>
            <label for="Max">Max: </label>
            <InputNumber id="Max" @bind-Value="myData.Max"/>
            <ValidationMessage For="() => myData.Max"/>
        </p>
        <p>
            <label for="BirthDate">BirthDate: </label>
            <InputDate id="BirthDate" @bind-Value="myData.BirthDate"/>
            <ValidationMessage For="() => myData.BirthDate"/>
        </p>
        <p>
            <label for="Password">Password: </label>
            <InputText id="Password" @bind-Value="myData.Password" 
                       type="password"/>
            <ValidationMessage For="() => myData.Password"/>
        </p>
        <p>
            <label for="ConfirmPassword">ConfirmPassword: </label>
            <InputText id="ConfirmPassword" @bind-Value="myData.ConfirmPassword" 
                       type="password"/>
            <ValidationMessage For="() => myData.ConfirmPassword"/>
        </p>
    
        <button type="submit">Submit</button>
    </EditForm>
    
    @code {
        private readonly MyData myData = new();
    
        private void HandleValidSubmit()
        {
        // Save the data
        }
    }
    

    Output: How to show validation in Blazor form