Input placeholder from ViewModel metadata in ASP.NET Core 1.0

regnauld picture regnauld · Mar 17, 2016 · Viewed 10.2k times · Source

Is it possible to set up the built-in asp-for tag helper to take the input placeholder from the [Display(Prompt = "This is the placeholder")] attribute in the view model.

[Display(Name="Name", Prompt = "This is the placeholder")]        
public string Name { get; set; }

In MVC 5 I am able to achieve this by adding additional logic in my editor templates and checking the ViewData.ModelMetadata.Watermark property. For example:

@model string
@{
    Dictionary<string, object> htmlAttributes = new Dictionary<string, object>();
    htmlAttributes.Add("class", "form-control");
    if (!string.IsNullOrWhiteSpace(ViewData.ModelMetadata.Watermark))
    {
        htmlAttributes.Add("placeholder", ViewData.ModelMetadata.Watermark);
    }
}
@Html.Label("")
@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, htmlAttributes)
@Html.ValidationMessage("", "", new { @class = "text-danger" })

But now in ASP.NET Core 1.0 I would like to start using the new tag helpers approach. By default, the build in asp-for helper simply ignores the Prompt attribute value.

Having my own custom implementation of the asp-for attribute, e.g. my-asp-for is an option and most probably I will end up having it for the sake of maintainability and reusing additional logic. But then the Watermark property is no longer present in the ModelMetadata, i.e. there is no such thing as For.Metadata.Watermark.

The only place I can see the Prompt value in the asp-for helper is somewhat hidden.

enter image description here

So I have two questions. Is there a smarter way to do that ? Is it a bad practice to take the placeholder from the viewmodel metadata, i.e. I should explicitly specify it it in the razor file ?

Answer

Sock picture Sock · Jun 17, 2016

I have just done a quick test and if I understand you correctly, this appears to work out of the box for me with the default VS template:

Model:

public class LoginViewModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email", Prompt = "[email protected]")]
    public string Email { get; set; }

    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }

    [Display(Name = "Remember me?")]
    public bool RememberMe { get; set; }
}

View snippet:

<div class="form-group">
    <label asp-for="Email" class="col-md-2 control-label"></label>
    <div class="col-md-10">
        <input asp-for="Email" class="form-control" />
        <span asp-validation-for="Email" class="text-danger"></span>
    </div>
</div>

Result:

enter image description here