Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions src/Components/Web/src/Forms/Label.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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>
/// Renders a <c>&lt;label&gt;</c> element for a specified field, reading the display name from
/// <see cref="System.ComponentModel.DataAnnotations.DisplayAttribute"/> or
/// <see cref="System.ComponentModel.DisplayNameAttribute"/> if present, or falling back to the property name.
/// The label wraps its child content (typically an input component), providing implicit association
/// without requiring matching for/id attributes.
/// </summary>
/// <typeparam name="TValue">The type of the field.</typeparam>
public class Label<TValue> : IComponent
{
private RenderHandle _renderHandle;
private Expression<Func<TValue>>? _previousFieldAccessor;
private string? _displayName;

/// <summary>
/// Specifies the field for which the label should be rendered.
/// </summary>
[Parameter, EditorRequired]
public Expression<Func<TValue>>? For { get; set; }

/// <summary>
/// Gets or sets the child content to be rendered inside the label element.
/// Typically this contains an input component that will be implicitly associated with the label.
/// </summary>
[Parameter]
public RenderFragment? ChildContent { get; set; }

/// <summary>
/// Gets or sets a collection of additional attributes that will be applied to the label element.
/// </summary>
[Parameter(CaptureUnmatchedValues = true)]
public IReadOnlyDictionary<string, object>? AdditionalAttributes { get; set; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if user adds for attribute manually?


/// <inheritdoc />
void IComponent.Attach(RenderHandle renderHandle)
{
_renderHandle = renderHandle;
}

/// <inheritdoc />
Task IComponent.SetParametersAsync(ParameterView parameters)
{
parameters.SetParameterProperties(this);

if (For is null)
{
throw new InvalidOperationException($"{GetType()} requires a value for the " +
$"{nameof(For)} parameter.");
}

// Only recalculate if the expression changed
if (For != _previousFieldAccessor)
{
_displayName = ExpressionMemberAccessor.GetDisplayName(For);
_previousFieldAccessor = For;
}

_renderHandle.Render(BuildRenderTree);

return Task.CompletedTask;
}

private void BuildRenderTree(RenderTreeBuilder builder)
{
builder.OpenElement(0, "label");
builder.AddMultipleAttributes(1, AdditionalAttributes);
builder.AddContent(2, _displayName);
builder.AddContent(3, ChildContent);
builder.CloseElement();
}
}
8 changes: 8 additions & 0 deletions src/Components/Web/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,11 @@ Microsoft.AspNetCore.Components.Forms.DisplayName<TValue>
Microsoft.AspNetCore.Components.Forms.DisplayName<TValue>.DisplayName() -> void
Microsoft.AspNetCore.Components.Forms.DisplayName<TValue>.For.get -> System.Linq.Expressions.Expression<System.Func<TValue>!>?
Microsoft.AspNetCore.Components.Forms.DisplayName<TValue>.For.set -> void
Microsoft.AspNetCore.Components.Forms.Label<TValue>
Microsoft.AspNetCore.Components.Forms.Label<TValue>.AdditionalAttributes.get -> System.Collections.Generic.IReadOnlyDictionary<string!, object!>?
Microsoft.AspNetCore.Components.Forms.Label<TValue>.AdditionalAttributes.set -> void
Microsoft.AspNetCore.Components.Forms.Label<TValue>.ChildContent.get -> Microsoft.AspNetCore.Components.RenderFragment?
Microsoft.AspNetCore.Components.Forms.Label<TValue>.ChildContent.set -> void
Microsoft.AspNetCore.Components.Forms.Label<TValue>.For.get -> System.Linq.Expressions.Expression<System.Func<TValue>!>?
Microsoft.AspNetCore.Components.Forms.Label<TValue>.For.set -> void
Microsoft.AspNetCore.Components.Forms.Label<TValue>.Label() -> void
Loading
Loading