Reputation: 1746
I want to simplify my code by wrapping a large chunk of form code into a seperate component.
What I did was creating MyInput.razor which holds the following code:
<div class="@ColSize">
<label>@Label</label>
<InputText @bind-Value="Value" class="form-control" />
<ValidationMessage For="() => Value" />
</div>
@code {
public string ColSize { get; set; } = "col-md-12";
[Parameter]
public string Label { get; set; } = string.Empty;
[Parameter]
public string? Value { get; set; }
[Parameter]
public EventCallback<string?> ValueChanged { get; set; }
}
In my Index.razor I've added a simple form with basic validation like this:
<EditForm Model="Input" OnValidSubmit="Submit">
<DataAnnotationsValidator />
<ValidationSummary />
<MyInput @bind-Value="Input.Name" />
<button type="submit" class="d-block mt-3">Save</button>
</EditForm>
@code {
public MyModel Input { get; set; } = new();
private void Submit()
{
}
public class MyModel
{
[MinLength(10)]
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
}
}
The validation and the binding is working, however, I don't see the validation errors for <ValidationMessage For="() => Value" />
in my component. I can only see the messages with the ValidationSummary.
Is there any easy way to get this working? I don't want to create a new component which inherits from InputText
or InputBase
. I just want to use the existing input types and wrap some HTML around it so I don't have to type it everytime again.
Upvotes: 2
Views: 4019
Reputation: 1501
It could be better to inherit your component from InputBase<string>
in this case, then you do not need to provide expression for validation.
Also, you can read label from Display data annotation attribute.
@using System.ComponentModel.DataAnnotations
@using System.Reflection
@inherits InputBase<string>
<div class="@CssClass field">
@if (!string.IsNullOrWhiteSpace(this.Label))
{
<label class="field__label">@Label</label>
}
<input class="form-field__input" @bind="@CurrentValue" />
@if (this.ValueExpression != null)
{
<ValidationMessage class="field__validation-message" For=@ValueExpression />
}
</div>
@code {
private string? Label
{
get
{
if (ValueExpression != null)
if (ValueExpression.Body is MemberExpression memberExpression)
return (memberExpression.Member as PropertyInfo)?.GetCustomAttribute<DisplayAttribute>()?.GetName();
return null;
}
}
protected override bool TryParseValueFromString(string? value, out string result, out string validationErrorMessage)
{
result = value ?? string.Empty;
validationErrorMessage = string.Empty;
return true;
}
}
Usage:
<EditForm Model="ViewModel" OnValidSubmit="Submit">
<DataAnnotationsValidator />
<ValidationSummary />
<TextualField @bind-Value="ViewModel.Email" />
<SecretField @bind-Value="ViewModel.Password" />
<button type="submit">Save</button>
</EditForm>
Upvotes: 0
Reputation: 14553
<ValidationMessage
uses and expression to get to the model EditForm is using. You need to pass the expression into your component.
<div class="@ColSize">
<label>@Label</label>
<InputText @bind-Value="Value" class="form-control" />
<ValidationMessage For=@For />
</div>
@code {
public string ColSize { get; set; } = "col-md-12";
[Parameter] public string Label { get; set; } = string.Empty;
[Parameter] public string? Value { get; set; }
[Parameter] public Expression<Func<TValue>>? For { get; set; }
[Parameter] public EventCallback<string?> ValueChanged { get; set; }
}
Usage:
<MyInput @bind-Value="Input.Name" For="() => Input.Name" />
Source code for ValidationMessage
Upvotes: 5