I have a Blazor server app that has a form with two password inputs, "new password" and "confirm password". I'm using DataAnnotations Compare
attribute to validate that the two match. I've also tried the CompareProperty
attribute from the experimental NuGet package Microsoft.AspNetCore.Components.DataAnnotations.Validation
, but the behavior is the same.
The sample page below is able to reproduce the error in Chrome and Edge. Testing steps:
Just from personal experience, I sometimes add extra characters to the end of passwords suggested by Chrome, mostly to satisfy complexity requirements the generated password didn't meet. So this form behavior will be problematic if my users do the same. Anyone know what's going on here and how to solve it?
Index.razor:
@page "/"
@using System.ComponentModel.DataAnnotations;
<PageTitle>Index</PageTitle>
<EditForm name="passwordForm" Model="MyModel" OnSubmit="@SubmitPasswordForm">
<DataAnnotationsValidator />
<div class="form-group">
<label for="NewPassword">New Password</label>
<InputText @bind-Value="MyModel.NewPassword" class="form-control" id="NewPassword" name="NewPassword" type="password" autocomplete="new-password"></InputText>
<ValidationMessage For="@(() => MyModel.NewPassword)" />
</div>
<div class="form-group">
<label for="ConfirmNewPassword">Confirm Password</label>
<InputText @bind-Value="MyModel.ConfirmPassword" class="form-control" id="ConfirmNewPassword" name="ConfirmNewPassword" type="password" autocomplete="new-password"></InputText>
<ValidationMessage For="@(() => MyModel.ConfirmPassword)" />
</div>
<input id="submitResetPassword" type="submit" class="btn btn-default" value="Reset Password" />
</EditForm>
@code {
private Model MyModel { get; set; } = new();
private void SubmitPasswordForm()
{
// Do something with the password
}
private class Model
{
[Required]
public string? NewPassword { get; set; }
[Required]
[Compare(nameof(NewPassword))]
// or [CompareProperty(nameof(NewPassword))]
public string? ConfirmPassword { get; set; }
}
}
I tried to reproduce your issue:
trigger validate onblur may solve your issue:
@using System.ComponentModel.DataAnnotations;
<EditForm name="passwordForm" EditContext="@EC" OnSubmit="@SubmitPasswordForm">
<DataAnnotationsValidator />
<div class="form-group">
<label for="NewPassword">New Password</label>
<InputText @bind-Value="MyModel.NewPassword" class="form-control" id="NewPassword" name="NewPassword" type="password" autocomplete="new-password" onblur="@OnblurHandler"></InputText>
<ValidationMessage For="@(() => MyModel.NewPassword)" />
</div>
<div class="form-group">
<label for="ConfirmNewPassword">Confirm Password</label>
<InputText @bind-Value="MyModel.ConfirmPassword" class="form-control" id="ConfirmNewPassword" name="ConfirmNewPassword" type="password" autocomplete="new-password" ></InputText>
<ValidationMessage For="@(() => MyModel.ConfirmPassword)" />
</div>
<input id="submitResetPassword" type="submit" class="btn btn-default" value="Reset Password" />
</EditForm>
@code {
private Model MyModel { get; set; } = new();
private void SubmitPasswordForm()
{
// Do something with the password
}
protected override void OnInitialized()
{
EC = new EditContext(MyModel);
base.OnInitialized();
}
private void OnblurHandler()
{
EC.Validate(); // manually trigger the validation here
}
private EditContext EC { get; set; }
private class Model
{
[Required]
public string? NewPassword { get; set; }
[Required]
[Compare(nameof(NewPassword))]
// or [CompareProperty(nameof(NewPassword))]
public string? ConfirmPassword { get; set; }
}
}