Permalink
Cannot retrieve contributors at this time
102 lines (88 sloc)
3.58 KB
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
// Licensed to the .NET Foundation under one or more agreements. | |
// The .NET Foundation licenses this file to you under the MIT license. | |
using System.Linq.Expressions; | |
using Microsoft.AspNetCore.Components.Rendering; | |
namespace Microsoft.AspNetCore.Components.Forms; | |
/// <summary> | |
/// Displays a list of validation messages for a specified field within a cascaded <see cref="EditContext"/>. | |
/// </summary> | |
public class ValidationMessage<TValue> : ComponentBase, IDisposable | |
{ | |
private EditContext? _previousEditContext; | |
private Expression<Func<TValue>>? _previousFieldAccessor; | |
private readonly EventHandler<ValidationStateChangedEventArgs>? _validationStateChangedHandler; | |
private FieldIdentifier _fieldIdentifier; | |
/// <summary> | |
/// Gets or sets a collection of additional attributes that will be applied to the created <c>div</c> element. | |
/// </summary> | |
[Parameter(CaptureUnmatchedValues = true)] public IReadOnlyDictionary<string, object>? AdditionalAttributes { get; set; } | |
[CascadingParameter] EditContext CurrentEditContext { get; set; } = default!; | |
/// <summary> | |
/// Specifies the field for which validation messages should be displayed. | |
/// </summary> | |
[Parameter] public Expression<Func<TValue>>? For { get; set; } | |
/// <summary>` | |
/// Constructs an instance of <see cref="ValidationMessage{TValue}"/>. | |
/// </summary> | |
public ValidationMessage() | |
{ | |
_validationStateChangedHandler = (sender, eventArgs) => StateHasChanged(); | |
} | |
/// <inheritdoc /> | |
protected override void OnParametersSet() | |
{ | |
if (CurrentEditContext == 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; | |
} | |
if (CurrentEditContext != _previousEditContext) | |
{ | |
DetachValidationStateChangedListener(); | |
CurrentEditContext.OnValidationStateChanged += _validationStateChangedHandler; | |
_previousEditContext = CurrentEditContext; | |
} | |
} | |
/// <inheritdoc /> | |
protected override void BuildRenderTree(RenderTreeBuilder builder) | |
{ | |
foreach (var message in CurrentEditContext.GetValidationMessages(_fieldIdentifier)) | |
{ | |
builder.OpenElement(0, "div"); | |
builder.AddAttribute(1, "class", "validation-message"); | |
builder.AddMultipleAttributes(2, AdditionalAttributes); | |
builder.AddContent(3, message); | |
builder.CloseElement(); | |
} | |
} | |
/// <summary> | |
/// Called to dispose this instance. | |
/// </summary> | |
/// <param name="disposing"><see langword="true"/> if called within <see cref="IDisposable.Dispose"/>.</param> | |
protected virtual void Dispose(bool disposing) | |
{ | |
} | |
void IDisposable.Dispose() | |
{ | |
DetachValidationStateChangedListener(); | |
Dispose(disposing: true); | |
} | |
private void DetachValidationStateChangedListener() | |
{ | |
if (_previousEditContext != null) | |
{ | |
_previousEditContext.OnValidationStateChanged -= _validationStateChangedHandler; | |
} | |
} | |
} |