Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get "Display name" on the label of in Blazor's razor page?

Tags:

c#

razor

blazor

I have the following model:

class User
{
    [Display(Name = "Display Name")]
    public string Name { get; set; }
}

In standard Razor I would do something like the following to get the "Display Name":

<label asp-for="Model.Name"></label>

but that doesn't seem to work in Blazor. Does anyone know how to get the display name in a Blazor page without using reflection?

like image 716
user3224222 Avatar asked Jul 25 '19 12:07

user3224222


3 Answers

My implementation is to replace the Html.DisplayNameFor() method from regular Razor;

@using System.Reflection
@using System.Linq.Expressions;
@using System.ComponentModel.DataAnnotations;
@typeparam T
@if (ChildContent == null)
{
    <label>@label</label>
}
else
{
    <label>
        @label
        @ChildContent
    </label>
}
@code {
    [Parameter] public Expression<Func<T>> For { get; set; }
    [Parameter] public RenderFragment ChildContent { get; set; }

    private string label => GetDisplayName();

    private string GetDisplayName()
    {
        var expression = (MemberExpression)For.Body;
        var value = expression.Member.GetCustomAttribute(typeof(DisplayAttribute)) as DisplayAttribute;
        return value?.Name ?? expression.Member.Name ?? "";
    }
}

with this at the call site, either:

<DisplayName For="@(() => object.Member)" />

or

<DisplayName For="@(() => object.Member)">
    <InputText @bind-Value="object.Member" />
</DisplayName>

Edit: to clarify, the two versions produce slightly different markup. The first would produce:

<label>Generated DisplayName</label>

And the second would produce

<label>
    Generated DisplayName
    <input value="WhateverTheValueIs" />
</label>

Additionally, in my implementation I added a bool property to allow just plaintext output - since it turned out there was lots of times I just wanted the display name text out.

like image 123
Kruft Avatar answered Nov 19 '22 17:11

Kruft


@BlackFenix2 I'm not allowed to comment (yet 😉) but <Label For="@(() => Model.Name))" /> should be <Label For="@(() => Model.Name)" /> One ')' to many

And to enhance your solution somewhat I've added @attributes="AdditionalAttributes" so you can do this (for example) <Label class="col-3 col-form-label" For="@(() => Model.Name)" />

@using System.Reflection
@using System.ComponentModel
@using System.Linq.Expressions;

<label @attributes="AdditionalAttributes">@label</label>

@code {
    [Parameter] public Expression<Func<string>> For { get; set; }

    [Parameter(CaptureUnmatchedValues = true)]
    public IDictionary<string, object> AdditionalAttributes { get; set; }

    private string label => GetDisplayName();

    private string GetDisplayName()
    {
        var expression = (MemberExpression)For.Body;
        var value = expression.Member.GetCustomAttribute(typeof(DisplayNameAttribute)) as DisplayNameAttribute;
        return value?.DisplayName ?? expression.Member.Name ?? "";
    }
}
like image 24
Jaap Avatar answered Nov 19 '22 17:11

Jaap


Bad news:

At this time (preview7), they are not an out of the box feature to do it.

Good news:

It's very easy to create your own custom label component (using a bit reflection of course) and encapsulate functionality in it:

@using System.Linq
@using System.Reflection
@using System.ComponentModel.DataAnnotations

@typeparam TItem

<label for="@fortag">@label</label>

@code {
    [Parameter] public string aspfor { get; set; }        

    private string label => GetDisplayName(aspfor);

    private string fortag => aspfor;

    private string GetDisplayName(string propertyname)
    {
        MemberInfo myprop = typeof(TItem).GetProperty(propertyname) as MemberInfo;
        var dd = myprop.GetCustomAttribute(typeof(DisplayAttribute)) as DisplayAttribute;
        return dd?.Name ?? "";
    }

}

And use it in your .razor page:

<CustomLabel TItem="User" aspfor="@nameof(User.Name)"></CustomLabel>

Be free to improve it with Expressions or more typed code (as @issac explains in their answer) and come back to us to explain your experience.

Demo:

Try it at blazorfiddle.

like image 11
dani herrera Avatar answered Nov 19 '22 15:11

dani herrera