Last active
April 6, 2024 00:03
-
-
Save bcheung4589/be0f762c7eeaab3655b4eb9041be4f0b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNetCore.Components; | |
using Microsoft.AspNetCore.Components.Forms; | |
using System.Collections.Concurrent; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
namespace Pfx.Web.ComponentsLibrary.Forms; | |
/// <summary> | |
/// Displays a list of validation messages for a specified field within a cascaded <see cref="EditContext"/>. | |
/// </summary> | |
public class PfxValidationMessage<TValue> : ValidationMessage<TValue> | |
{ | |
private static readonly ConcurrentDictionary<(Type ModelType, MemberInfo Member), Func<object, object>> _fieldAccessors = new(); | |
private EditContext? _previousEditContext; | |
private Expression<Func<TValue>>? _previousFieldAccessor; | |
private readonly EventHandler<ValidationStateChangedEventArgs>? _validationStateChangedHandler; | |
private FieldIdentifier _fieldIdentifier; | |
[CascadingParameter] EditContext NestedEditContext { get; set; } = default!; | |
/// <summary>` | |
/// Constructs an instance of <see cref="PfxValidationMessage{TValue}"/>. | |
/// </summary> | |
public PfxValidationMessage() | |
{ | |
_validationStateChangedHandler = (sender, eventArgs) => StateHasChanged(); | |
} | |
/// <inheritdoc /> | |
protected override void OnParametersSet() | |
{ | |
if (NestedEditContext == null) | |
{ | |
throw new InvalidOperationException($"{GetType()} requires a cascading parameter of type {nameof(EditContext)}. For example, you can use {GetType()} inside an {nameof(EditForm)}."); | |
} | |
if (For == null) // Not possible except if you manually specify T | |
{ | |
throw new InvalidOperationException($"{GetType()} requires a value for the {nameof(For)} parameter."); | |
} | |
else if (For != _previousFieldAccessor) | |
{ | |
_fieldIdentifier = FieldIdentifier.Create(For); | |
_previousFieldAccessor = For; | |
//# fix to validate nested properties. | |
NestedEditContext.NotifyFieldChanged(_fieldIdentifier); | |
} | |
if (NestedEditContext != _previousEditContext) | |
{ | |
DetachValidationStateChangedListener(); | |
NestedEditContext.OnValidationStateChanged += _validationStateChangedHandler; | |
_previousEditContext = NestedEditContext; | |
} | |
} | |
/// <inheritdoc /> | |
protected override void BuildRenderTree(RenderTreeBuilder builder) | |
{ | |
foreach (var message in NestedEditContext.GetValidationMessages(_fieldIdentifier)) | |
{ | |
builder.OpenElement(0, "div"); | |
builder.AddAttribute(1, "class", "validation-message"); | |
builder.AddMultipleAttributes(2, AdditionalAttributes); | |
builder.AddContent(3, message); | |
builder.CloseElement(); | |
} | |
} | |
private void DetachValidationStateChangedListener() | |
{ | |
if (_previousEditContext != null) | |
{ | |
_previousEditContext.OnValidationStateChanged -= _validationStateChangedHandler; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
The addition of L49 ensures the EditContext triggers the validation on the specified (nested) field.
This trigger will ensure "NestedEditContext.GetValidationMessages(field)" has messages in case of invalid input on: L63