Adding DisplayName, Label HtmlHelpers.

This commit is contained in:
harshgMSFT 2014-04-10 13:54:55 -07:00
parent b9b652084a
commit 72732868c6
7 changed files with 312 additions and 36 deletions

View File

@ -18,9 +18,9 @@
display: none;
}
#qux.foo {
color: red;
}
#qux.foo {
color: red;
}
</style>
}
@ -40,7 +40,7 @@
{
return "Hello World";
}
public Task RenderHelloWorldPartial(User model)
{
// Imagine this method was a super complex method that was used as a helper method.
@ -55,13 +55,15 @@
</div>
<div class="row">
<h3 title="@Model.Name" class="@nullValue">Hello @Model.Name! Happy @Model.Age birthday.</h3>
<h3 id ="qux">This value was retrieved asynchronously: @(await AsyncValueRetrieval())</h3>
<h3 id="qux">This value was retrieved asynchronously: @(await AsyncValueRetrieval())</h3>
<h3>Partial Async: @await Html.PartialAsync("HelloWorldPartial", Model)</h3>
<h3>Render Partial Async (Custom model): @{ await RenderHelloWorldPartial(new User()
<h3>
Render Partial Async (Custom model): @{ await RenderHelloWorldPartial(new User()
{
Name="Bob"
});
}</h3>
});
}
</h3>
<div class="col-md-4">
<h2>Book a flight</h2>
@ -87,7 +89,10 @@
<table>
<tr>
<td>
<label class="control-label col-md-2">ForModel</label>
@Html.LabelForModel("ForModel")
</td>
<td>
'@Html.DisplayNameForModel()'
</td>
<td>
'@Html.NameForModel()'
@ -98,7 +103,10 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Name</label>
@Html.Label("Name")
</td>
<td>
'@Html.DisplayName("Name")'
</td>
<td>
'@Html.Name("Name")'
@ -109,7 +117,10 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">m.Address</label>
@Html.LabelFor(m => m.Address)
</td>
<td>
'@Html.DisplayNameFor(m => m.Address)'
</td>
<td>
'@Html.NameFor(m => m.Address)'
@ -120,7 +131,10 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Anon.Address.Street</label>
@Html.Label("Anon.Address.Street")
</td>
<td>
'@Html.DisplayName("Anon.Address.Street")'
</td>
<td>
'@Html.Name("Anon.Address.Street")'
@ -146,7 +160,7 @@
<table>
<tr>
<td>
<label class="control-label col-md-2">Model.Name</label>
@Html.Label("Name")
</td>
<td>
@Html.TextBox("Name")
@ -154,7 +168,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Model.Address</label>
@Html.LabelFor(m => m.Address, htmlAttributes: new { @class="control-label col-md-2" })
</td>
<td>
@Html.TextBoxFor(m => m.Address, htmlAttributes: new { @class = "form-control" })
@ -162,7 +176,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Model.Alive</label>
@Html.Label("Alive")
</td>
<td>
@Html.CheckBox("Alive")
@ -173,7 +187,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Model.Dependent.Alive</label>
@Html.LabelFor(m => m.Dependent.Alive)
</td>
<td>
@Html.CheckBoxFor(m => m.Dependent.Alive)
@ -184,7 +198,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Model.Password</label>
@Html.LabelFor(model => model.Password, htmlAttributes: new { @class="control-label col-md-2" })
</td>
<td>
@Html.PasswordFor(m => m.Password, htmlAttributes: new { @class = "form-control" })
@ -203,7 +217,7 @@
<table>
<tr>
<td>
<label class="control-label col-md-2">Anon.Name</label>
@Html.Label("Anon.Name")
</td>
<td>
@Html.TextBox("Anon.Name")
@ -211,7 +225,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Anon.Address.Street</label>
@Html.Label("Anon.Address.Street")
</td>
<td>
@Html.TextBox("Anon.Address.Street", (object)ViewBag.Anon.Address.Street)
@ -219,7 +233,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Anon.Address.City</label>
@Html.Label("Anon.Address.City")
</td>
<td>
@Html.TextBox("Anon.Address.City", value: null, format: "{0} (3)")
@ -227,7 +241,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Anon.Address.State</label>
@Html.Label("Anon.Address.State")
</td>
<td>
@Html.TextBox("Anon.Address.State", value: null, htmlAttributes: new { @class = "form-control" })
@ -235,16 +249,16 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Anon.Address.Country</label>
@Html.Label("Anon.Address.Country")
</td>
<td>
@Html.TextBox("Anon.Address.Country", value: null, format: "{0} (4)",
htmlAttributes: new { @class = "form-control" })
htmlAttributes: new { @class = "form-control" })
</td>
</tr>
<tr>
<td>
<label class="control-label col-md-2">Password</label>
@Html.Label("Password")
</td>
<td>
@Html.Password("Password", "some string")
@ -266,7 +280,7 @@
<table>
<tr>
<td>
<label class="control-label col-md-2">Display Name</label>
@Html.Label("Name", "Display Name")
</td>
<td>
'@Html.Display("Name")'
@ -274,7 +288,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Display Dependent.Name</label>
@Html.Label("Dependent.Name", "Display Dependent.Name")
</td>
<td>
'@Html.Display("Dependent.Name")'
@ -282,7 +296,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Display Alive</label>
@Html.Label("Alive", "Display Alive")
</td>
<td>
'@Html.Display("Alive")'
@ -290,7 +304,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Display Dependent.Alive</label>
@Html.Label("Dependent.Alive", "Display Dependent.Alive")
</td>
<td>
'@Html.Display("Dependent.Alive")'
@ -298,7 +312,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Display Age</label>
@Html.Label("Age", "Display Age")
</td>
<td>
'@Html.Display("Age")'
@ -306,7 +320,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">Display GPA</label>
@Html.Label("GPA", "Display GPA")
</td>
<td>
'@Html.Display("GPA")'
@ -318,7 +332,7 @@
<table>
<tr>
<td>
<label class="control-label col-md-2">DisplayFor Name</label>
@Html.LabelFor(model => model.Name, "DisplayFor Name")
</td>
<td>
'@Html.DisplayFor(model => model.Name)'
@ -326,7 +340,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">DisplayFor Dependent.Name</label>
@Html.LabelFor(model => model.Dependent.Name, "DisplayFor Dependent.Name")
</td>
<td>
'@Html.DisplayFor(model => model.Dependent.Name)'
@ -334,7 +348,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">DisplayFor Alive</label>
@Html.LabelFor(model => model.Alive, "DisplayFor Alive")
</td>
<td>
'@Html.DisplayFor(model => model.Alive)'
@ -342,7 +356,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">DisplayFor Dependent.Alive</label>
@Html.LabelFor(model => model.Dependent.Alive, "DisplayFor Dependent.Alive")
</td>
<td>
'@Html.DisplayFor(model => model.Dependent.Alive)'
@ -350,7 +364,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">DisplayFor Age</label>
@Html.LabelFor(model => model.Age, "DisplayFor Age")
</td>
<td>
'@Html.DisplayFor(model => model.Age)'
@ -358,7 +372,7 @@
</tr>
<tr>
<td>
<label class="control-label col-md-2">DisplayFor GPA</label>
@Html.LabelFor(model => model.GPA, "DisplayFor GPA")
</td>
<td>
'@Html.DisplayFor(model => model.GPA)'

View File

@ -141,7 +141,9 @@
<Compile Include="Rendering\HtmlHelperDisplayExtensions.cs" />
<Compile Include="Rendering\HtmlHelperFormExtensions.cs" />
<Compile Include="Rendering\HtmlHelperInputExtensions.cs" />
<Compile Include="Rendering\HtmlHelperLabelExtensions.cs" />
<Compile Include="Rendering\HtmlHelperLinkExtensions.cs" />
<Compile Include="Rendering\HtmlHelperDisplayNameExtensions.cs" />
<Compile Include="Rendering\HtmlHelperNameExtensions.cs" />
<Compile Include="Rendering\HtmlHelperPartialExtensions.cs" />
<Compile Include="Rendering\HtmlHelperSelectExtensions.cs" />

View File

@ -224,6 +224,18 @@ namespace Microsoft.AspNet.Mvc.Rendering
templateName,
additionalViewData);
}
public HtmlString DisplayName(string expression)
{
var modelMetadata = string.IsNullOrEmpty(expression) ?
ViewData.ModelMetadata :
ExpressionMetadataProvider.FromStringExpression(
expression,
ViewData,
MetadataProvider);
return GenerateDisplayName(modelMetadata, expression);
}
public HtmlString DropDownList(string name, IEnumerable<SelectListItem> selectList, string optionLabel,
object htmlAttributes)
@ -241,6 +253,22 @@ namespace Microsoft.AspNet.Mvc.Rendering
return GenerateHidden(metadata: null, name: name, value: value, useViewData: (value == null),
htmlAttributes: htmlAttributes);
}
public HtmlString Label(string expression, string labelText, object htmlAttributes)
{
var modelMetadata = string.IsNullOrEmpty(expression)?
ViewData.ModelMetadata :
ExpressionMetadataProvider.FromStringExpression(
expression,
ViewData,
MetadataProvider);
return GenerateLabel(
modelMetadata,
expression,
labelText,
htmlAttributes);
}
public virtual HtmlString Name(string name)
{
@ -543,6 +571,23 @@ namespace Microsoft.AspNet.Mvc.Rendering
format: null,
htmlAttributes: htmlAttributeDictionary);
}
protected virtual HtmlString GenerateDisplayName([NotNull] ModelMetadata metadata, string htmlFieldName)
{
// We don't call ModelMetadata.GetDisplayName here because
// we want to fall back to the field name rather than the ModelType.
// This is similar to how the GenerateLabel get the text of a label.
// TODO: This needs to be updated after ModelMetadata has a DisplayName property
var resolvedDisplayName = metadata.PropertyName;
if (resolvedDisplayName == null)
{
resolvedDisplayName = string.IsNullOrEmpty(htmlFieldName) ?
string.Empty :
htmlFieldName.Split('.').Last();
}
return new HtmlString(Encode(resolvedDisplayName));
}
protected HtmlString GenerateDropDown(ModelMetadata metadata, string expression,
IEnumerable<SelectListItem> selectList, string optionLabel, object htmlAttributes)
@ -632,6 +677,36 @@ namespace Microsoft.AspNet.Mvc.Rendering
format: null,
htmlAttributes: htmlAttributeDictionary);
}
protected virtual HtmlString GenerateLabel([NotNull] ModelMetadata metadata,
string htmlFieldName,
string labelText,
object htmlAttributes)
{
// TODO: This needs to be updated after ModelMetadata has a DisplayName property
string resolvedLabelText = labelText ?? metadata.PropertyName;
if (resolvedLabelText == null)
{
resolvedLabelText = string.IsNullOrEmpty(htmlFieldName) ?
string.Empty :
htmlFieldName.Split('.').Last();
}
if (string.IsNullOrEmpty(resolvedLabelText))
{
return HtmlString.Empty;
}
TagBuilder tag = new TagBuilder("label");
tag.Attributes.Add(
"for",
TagBuilder.CreateSanitizedId(
ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName),
IdAttributeDotReplacement));
tag.SetInnerText(resolvedLabelText);
tag.MergeAttributes(AnonymousObjectToHtmlAttributes(htmlAttributes), replaceExisting: true);
return tag.ToHtmlString(TagRenderMode.Normal);
}
protected virtual HtmlString GenerateLink(
[NotNull] string linkText,

View File

@ -82,6 +82,31 @@ namespace Microsoft.AspNet.Mvc.Rendering
additionalViewData);
}
/// <inheritdoc />
public HtmlString DisplayNameFor<TValue>([NotNull] Expression<Func<TModel, TValue>> expression)
{
var metadata = GetModelMetadata(expression);
return GenerateDisplayName(metadata, ExpressionHelper.GetExpressionText(expression));
}
/// <inheritdoc />
public HtmlString DisplayNameForInnerType<TInnerModel, TValue>(Expression<Func<TInnerModel, TValue>> expression)
{
var metadata = ExpressionMetadataProvider.
FromLambdaExpression<TInnerModel, TValue>(
expression,
new ViewDataDictionary<TInnerModel>(
MetadataProvider),
MetadataProvider);
var expressionText = ExpressionHelper.GetExpressionText(expression);
if (metadata == null)
{
throw new InvalidOperationException(Resources.FormatHtmlHelper_NullModelMetadata(expressionText));
}
return GenerateDisplayName(metadata, expressionText);
}
/// <inheritdoc />
public HtmlString HiddenFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression,
object htmlAttributes)
@ -91,6 +116,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
htmlAttributes: htmlAttributes);
}
/// <inheritdoc />
public HtmlString LabelFor<TValue>([NotNull] Expression<Func<TModel, TValue>> expression, string labelText, object htmlAttributes)
{
var metadata = GetModelMetadata(expression);
return GenerateLabel(metadata, ExpressionHelper.GetExpressionText(expression), labelText, htmlAttributes);
}
/// <inheritdoc />
public HtmlString NameFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression)
{

View File

@ -0,0 +1,36 @@

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace Microsoft.AspNet.Mvc.Rendering
{
/// <summary>
/// DisplayName-related extensions for <see cref="HtmlHelper"/> and <see cref="IHtmlHelper{T}"/>.
/// </summary>
public static class HtmlHelperDisplayNameExtensions
{
/// <summary>
/// Gets the display name for the current model.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper{T}"/> instance that this method extends.</param>
/// <returns>An <see cref="HtmlString"/> that represents HTML markup.</returns>
public static HtmlString DisplayNameForModel<TModel>([NotNull] this IHtmlHelper<TModel> htmlHelper)
{
return htmlHelper.DisplayName(string.Empty);
}
/// <summary>
/// Gets the display name for the model.
/// </summary>
/// <param name="htmlHelper">The <see cref="IHtmlHelper{T}"/> instance that this method extends.</param>
/// <param name="expression">An expression that identifies the object that contains the display name.</param>
/// <returns>
/// The display name for the model.
/// </returns>
public static HtmlString DisplayNameFor<TInnerModel,TValue>(this IHtmlHelper<IEnumerable<TInnerModel>> htmlHelper,
Expression<Func<TInnerModel, TValue>> expression)
{
return htmlHelper.DisplayNameForInnerType<TInnerModel, TValue>(expression);
}
}
}

View File

@ -0,0 +1,65 @@
using System;
using System.Linq.Expressions;
namespace Microsoft.AspNet.Mvc.Rendering
{
public static class HtmlHelperLabelExtensions
{
public static HtmlString Label<TModel>([NotNull] this IHtmlHelper<TModel> html, string expression)
{
return html.Label(expression,
labelText: null,
htmlAttributes: null);
}
public static HtmlString Label<TModel>([NotNull] this IHtmlHelper<TModel> html,
string expression,
string labelText)
{
return html.Label(expression, labelText, htmlAttributes: null);
}
public static HtmlString LabelFor<TModel, TValue>([NotNull] this IHtmlHelper<TModel> html,
[NotNull] Expression<Func<TModel, TValue>> expression)
{
return html.LabelFor<TValue>(expression, labelText: null, htmlAttributes: null);
}
public static HtmlString LabelFor<TModel, TValue>([NotNull] this IHtmlHelper<TModel> html,
[NotNull] Expression<Func<TModel, TValue>> expression,
string labelText)
{
return html.LabelFor<TValue>(expression, labelText, htmlAttributes: null);
}
public static HtmlString LabelFor<TModel, TValue>([NotNull] this IHtmlHelper<TModel> html,
[NotNull] Expression<Func<TModel, TValue>> expression,
object htmlAttributes)
{
return html.LabelFor<TValue>(expression, labelText: null, htmlAttributes: htmlAttributes);
}
public static HtmlString LabelForModel<TModel>([NotNull] this IHtmlHelper<TModel> html)
{
return LabelForModel(html, labelText: null);
}
public static HtmlString LabelForModel<TModel>([NotNull] this IHtmlHelper<TModel> html, string labelText)
{
return html.Label(expression: string.Empty, labelText: labelText, htmlAttributes: null);
}
public static HtmlString LabelForModel<TModel>([NotNull] this IHtmlHelper<TModel> html,
object htmlAttributes)
{
return html.Label(expression: string.Empty, labelText: null, htmlAttributes: htmlAttributes);
}
public static HtmlString LabelForModel<TModel>([NotNull] this IHtmlHelper<TModel> html,
string labelText,
object htmlAttributes)
{
return html.Label(expression: string.Empty, labelText: labelText, htmlAttributes: htmlAttributes);
}
}
}

View File

@ -174,6 +174,34 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <returns>The HTML markup for each property in the model.</returns>
HtmlString DisplayForModel(string templateName, string htmlFieldName, object additionalViewData);
/// <summary>
/// Gets the display name.
/// </summary>
/// <param name="expression">An expression that identifies the object that contains the display name.</param>
/// <returns>
/// The display name.
/// </returns>
HtmlString DisplayName(string expression);
/// <summary>
/// Gets the display name for the model.
/// </summary>
/// <param name="expression">An expression that identifies the object that contains the display name.</param>
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <returns>
/// The display name for the model.
/// </returns>
HtmlString DisplayNameFor<TValue>(Expression<Func<TModel, TValue>> expression);
/// <summary>
/// Gets the display name for the inner model if the current model represents a collection.
/// </summary>
/// <typeparam name="TInnerModel">The type of the inner model</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <param name="expression">An expression that identifies the object that contains the display name.</param>
/// <returns>The display name for the inner model.</returns>
HtmlString DisplayNameForInnerType<TInnerModel, TValue>(Expression<Func<TInnerModel, TValue>> expression);
/// <summary>
/// Returns a single-selection HTML {select} element using the specified name of the form field,
/// list items, option label, and HTML attributes.
@ -269,6 +297,30 @@ namespace Microsoft.AspNet.Mvc.Rendering
HtmlString HiddenFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression,
object htmlAttributes);
/// <summary>
/// Returns an HTML label element and the property name of the property that is represented by the specified expression.
/// </summary>
/// <param name="expression">An expression that identifies the property to display.</param>
/// <param name="labelText">The label text.</param>
/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param>
/// <returns>
/// An HTML label element and the property name of the property that is represented by the expression.
/// </returns>
HtmlString Label(string expression, string labelText, object htmlAttributes);
/// <summary>
/// Returns an HTML label element and the property name of the property that is represented by the specified expression.
/// </summary>
/// <param name="expression">An expression that identifies the property to display.</param>
/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param>
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <returns>
/// An HTML label element and the property name of the property that is represented by the expression.
/// </returns>
HtmlString LabelFor<TValue>(Expression<Func<TModel, TValue>> expression,
string labelText,
object htmlAttributes);
/// <summary>
/// Gets the full HTML field name for the given expression <paramref name="name"/>.
/// </summary>