I have a label as
<%= Html.Label("");%>
i want to add content to label at runtime, unfortunately it doesn't take any other parameter to create id property for it. can't i create id property for it just similar to asp:label
thanks,
michaeld
No need to use the HtmlHelper functions always and everywhere if they don't fit your need. They're just supposed to make your life easier, not harder. Use good ole HTML here:
<label id="id_for_label"></label>
If you want to keep using HtmlHelper functions you can always create your own extension methods.
For example:
public static class LabelHelper
{
private static string HtmlAttributes(object htmlAttributes)
{
var builder = new StringBuilder();
foreach (PropertyDescriptor descriptor in
TypeDescriptor.GetProperties(htmlAttributes))
{
builder.AppendFormat(" {0}=\"{1}\" ", descriptor.Name,
descriptor.GetValue(htmlAttributes));
}
return builder.ToString();
}
public static MvcHtmlString MyLabel(this HtmlHelper htmlHelper,
string labelText, object htmlAttributes)
{
var attributes = HtmlAttributes(htmlAttributes);
return MvcHtmlString.Create(
String.Format("<label for=\"{0}\" {1}>{0}</label",
labelText, attributes.Trim()));
}
}
Then you can add a label to a view in the following manner:
<%: Html.MyLabel("Hello, World!", new { #id = "myLabel" })%>
The generated HTML is:
<label for="Hello, World!" id="myLabel">Hello, World!</label>
For MVC 3 such a helper function is already available:
http://msdn.microsoft.com/en-us/library/gg538318(v=VS.99).aspx
Related
I have an #html.textBox and I am woundering if I can define Label inside rather then using separate #html.label tag ...
many thanks
Textbox
#Html.TextBox("Input_AvailableMark_Element", null, new { id = #item.ElementID + "_AM", #class = "ElementAvailableMarks k-grid-input k-textbox_3" })
Label
#Html.Label("AvailableMark", null, new {#class ="inputTextLabel_Custom_1" })
The only way I can think of to do that is with usage of placeholder attribute:
#Html.TextBoxFor(model => model.SomeProperty, new { placeholder = Model.SomeProperty })
I'm assuming you are using DataAnnotations for your models. So for example if you want the Display attribute value to be in your placeholder then you need to write this extension method to fetch data annotation DISPLAY attribute:
public static class GetAttributeExtension
{
public static string GetDisplayName<TModel, TValue>(this TModel model, Expression<Func<TModel, TValue>> expression)
{
return GetDisplayName(expression);
}
public static string GetDisplayName<TModel, TValue>(Expression<Func<TModel, TValue>> expression)
{
var propertyName = ((MemberExpression)expression.Body).Member.Name;
return typeof(TModel).GetAttribute<DisplayAttribute>(propertyName).Name;
}
}
And then you can do something like this:
#Html.TextBoxFor(model => model.SomeProperty, new { placeholder = Model.GetDisplayName(m => m.SomeProperty) })
Depending on what browsers you need to support, the easiest option is as #Marko suggests, add the placeholder attribute.
http://www.w3schools.com/tags/att_input_placeholder.asp
However, if you need to support non-HTML5 compliant browsers, this will not work. There are some javascript libraries that will do this behavior for you
http://www.wduffy.co.uk/jLabel/
I have used jLabel before and it works pretty well, but is not without its problems.
Is it possible to customize the Html.ValidationMessageFor method so that it produces different HTML?
I want to do something similar to:
<div class="field-error-box">
<div class="top"></div>
<div class="mid"><p>This field is required.</p></div>
</div>
I am not sure if it's possible to use paragraph instead of default span, as it may make impossible for validation plugin to place error messages. But for div -s, thats easy - you could write custom html helper.
Something along these lines (may need further testing/coding). You will need to include the namespace of this static extension method in your view, or put this into System.Web.Mvc.Html directly.
public static class Validator
{
public static MvcHtmlString MyValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression)
{
TagBuilder containerDivBuilder = new TagBuilder("div");
containerDivBuilder.AddCssClass("field-error-box");
TagBuilder topDivBuilder = new TagBuilder("div");
topDivBuilder.AddCssClass("top");
TagBuilder midDivBuilder = new TagBuilder("div");
midDivBuilder.AddCssClass("mid");
midDivBuilder.InnerHtml = helper.ValidationMessageFor(expression).ToString();
containerDivBuilder.InnerHtml += topDivBuilder.ToString(TagRenderMode.Normal);
containerDivBuilder.InnerHtml += midDivBuilder.ToString(TagRenderMode.Normal);
return MvcHtmlString.Create(containerDivBuilder.ToString(TagRenderMode.Normal));
}
}
As you see, this uses default ValidationMessageFor method, to not interfere with validation-plugin error message processing.
And you use this simply, as default validation message helper
#Html.MyValidationMessageFor(model => model.SomeRequiredField)
I used another way:
public static MvcHtmlString DivValidationMessageFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
return MvcHtmlString.Create(htmlHelper.ValidationMessageFor(expression).ToString().Replace("span", "div"));
}
This way you can use the built in way, but replace the span with a div.
If you need any other overloads of the function, just duplicate as necessary.
You can implement your own ValidationMessageFor helper to emit your desired output or use some javascript to add/modify the rendered HTML code but the custom ValidationMessageFor implementation is the cleaner approach IMHO.
To implement your own ValidationMessageFor helper take a look at the ValidationExtensions.ValidationMessageFor and ValidationMessageHelper methods in the ASP.NET MVC source code.
Implementation Hints
Since GetFormContextForClientValidation is internal you have to work around that implementation by duplicating the internal functionality in your code:
FormContext formContext = htmlHelper.ViewContext.ClientValidationEnabled ? htmlHelper.ViewContext.FormContext : null;
Some other methods are private in ValidationExtensions like GetUserErrorMessageOrDefault you would need to duplicate that code too. What you can do to avoid duplicating code is to let ValidationExtentensions.ValidationMessageFor render the validation message string that is wrapped in a span and afterwards change the rendered string according to your requirements. Keep in mind that "null" is returned in case no error was found and that you'll need the data- HTML attributes in case you have unobtrusive JavaScript enabled.
You can download the ASP.NET MVC 3 source code from here
The only need for change of the default tag generation was in my case, that spans behavior results in anoying margin setups.
I resolved this by using 'display: block'
Maybe this helps some people..
Maybe you can put that code
string propertyName = ExpressionHelper.GetExpressionText(expression);
string name = helper.AttributeEncode(helper.ViewData.TemplateInfo.GetFullHtmlFieldName(propertyName));
if (helper.ViewData.ModelState[name] == null ||
helper.ViewData.ModelState[name].Errors == null ||
helper.ViewData.ModelState[name].Errors.Count == 0)
{
return MvcHtmlString.Empty;
}
on top of the answered function, so that the div doesn't appear on the form load.
I created ValidationMessageAsStringFor which just returns the error message as string. It is basically a simplified version of ValidationMessageFor:
public static MvcHtmlString ValidationMessageAsStringFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression)
{
var field = ExpressionHelper.GetExpressionText(expression);
string modelName = helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(field);
if (!helper.ViewData.ModelState.ContainsKey(modelName))
{
return null;
}
var modelState = helper.ViewData.ModelState[modelName];
var modelErrors = (modelState == null) ? null : modelState.Errors;
var modelError = ((modelErrors == null) || (modelErrors.Count == 0)) ? null : modelErrors.FirstOrDefault(m => !String.IsNullOrEmpty(m.ErrorMessage)) ?? modelErrors[0];
if (modelError == null)
{
return null;
}
var errorMessage = GetUserErrorMessageOrDefault(helper.ViewContext.HttpContext, modelError, modelState);
return MvcHtmlString.Create(errorMessage);
}
private static string GetUserErrorMessageOrDefault(HttpContextBase httpContext, ModelError error, ModelState modelState)
{
if (!string.IsNullOrEmpty(error.ErrorMessage))
{
return error.ErrorMessage;
}
if (modelState == null)
{
return null;
}
return modelState.Value?.AttemptedValue;
}
With this in place and after importing the namespace containing the new helper, just create the HTML code you need:
<div class="field-error-box">
<div class="top"></div>
<div class="mid"><p>#Html.ValidationMessageAsStringFor(m => m.FieldName)</p></div>
</div>
Yes, just use a metamodel for the field:
[MetadataType(typeof(YourMetaData))]
public partial class YOURCLASS
{
[Bind(Exclude = "objID")]
public class YourMetaData
{
[Required(AllowEmptyStrings = false, ErrorMessage = "Please enter a name")]
public object Name { get; set; }
}
}
Change your message at the ErrorMessage field :)
Hope this help :)
How do I create an ASP.Net MVC Helper for an Html.Label which takes in attributes?
Currently when I define an Html.TextBox I am able to pass in a list of attributes. Sort of like below:
new {disabled="disabled", #class="pcTextBoxWithoutPaddingDisabled"})%>
However, it does not look as though the Html.Label has this feature. As a result, I have to define my labels using the label tag. Sort of like below:
<label class="pcLabelBlackWithoutPadding">
I would like to be consistent I how my Html element get created.
So, how do I create an Html.Label that will take in a list of attributes?
Thanks for your help.
This is updated version for MVC3:
public static MvcHtmlString Label(this HtmlHelper helper, String htmlFieldName, String labelText, Object htmlAttributes)
{
ModelMetadata metadata = ModelMetadata.FromStringExpression(htmlFieldName, helper.ViewData);
String innerText = labelText ?? (metadata.DisplayName ?? (metadata.PropertyName ?? htmlFieldName.Split('.').Last()));
if (String.IsNullOrEmpty(innerText))
{
return MvcHtmlString.Empty;
}
TagBuilder tagBuilder = new TagBuilder("label");
tagBuilder.Attributes.Add("for", TagBuilder.CreateSanitizedId(helper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName)));
tagBuilder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
tagBuilder.SetInnerText(innerText);
return new MvcHtmlString(tagBuilder.ToString(TagRenderMode.Normal));
}
I have modified Alexandr code a bit with lambda expression, in case anyone needed the lambda expression.
usage:
#Html.LabelFor(model => model.Property , new { #class = "bigFont" })
code:
public static MvcHtmlString LabelFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression, Object htmlAttributes)
{
var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
var innerText = metadata.DisplayName ?? metadata.PropertyName;
if (String.IsNullOrEmpty(innerText))
{
return MvcHtmlString.Empty;
}
var tagBuilder = new TagBuilder("label");
tagBuilder.Attributes.Add("for", TagBuilder.CreateSanitizedId(htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(metadata.PropertyName)));
tagBuilder.MergeAttributes(new RouteValueDictionary(htmlAttributes));
tagBuilder.SetInnerText(innerText);
return new MvcHtmlString(tagBuilder.ToString(TagRenderMode.Normal));
}
I'd suggest creating your own HtmlHelper extension method and using a TagBuilder to create the label.
public static HtmlHelperExtensions
{
public static Label( this HtmlHelper helper, string labelText, object properties )
{
var builder = new TagBuilder("label");
builder.MergeAttributes( new RouteValueDictionary( properties ) );
builder.SetInnerText( labelText );
return builder.ToString( TagRenderMode.Normal );
}
}
See the MVC source code for ideas on how to create a strongly-typed label helper. Note that you'll need to add the namespace containing your extensions either to the page or the web.config to be able to use it.
How can I make up a RouteLink in a custom HtmlHelper? I know how to make it in a partial view but I want to build up a new link in a custom htmlhelper extension method with the use of a RouteLink. How to accomplish this?
Update: I noticed HtmlHelper.GenerateRouteLink. But what do I need to put in as parameters?
Here's an example. Let's suppose that you want to wrap the links into a div tag with some given class so that your resulting html looks like this:
<div class="foo">Some text</div>
You could write the following extension method:
public static class HtmlExtensions
{
public static MvcHtmlString CustomRouteLink(
this HtmlHelper htmlHelper,
string className,
string linkText,
object routeValues
)
{
var div = new TagBuilder("div");
div.MergeAttribute("class", className);
div.InnerHtml = htmlHelper.RouteLink(linkText, routeValues).ToHtmlString();
return MvcHtmlString.Create(div.ToString());
}
}
which could be used like this:
<%= Html.CustomRouteLink("foo", "Some text",
new { action = "index", controller = "home" }) %>
and this will produce the desired markup. Any other overloads of RouteLink could be used if necessary.
Once you get an instance of the UrlHelper you should be able to do whatever you want to do in your HtmlHelper method
UrlHelper url = new UrlHelper(helper.ViewContext.RequestContext);
i would like to change the way LabelFor render. Can i do that with a DisplayTemplate?
LabelFor generate a label tag and i would like to add a ":" at the end of the label.
thank you!
alex
Here is an HTML Helper that will do that:
public static class LabelExtensions {
[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
public static MvcHtmlString SmartLabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression) {
return LabelHelper(html,
ModelMetadata.FromLambdaExpression(expression, html.ViewData),
ExpressionHelper.GetExpressionText(expression));
}
internal static MvcHtmlString LabelHelper(HtmlHelper html, ModelMetadata metadata, string htmlFieldName) {
string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
if (String.IsNullOrEmpty(labelText)) {
return MvcHtmlString.Empty;
}
// uncomment if want * for required field
//if (metadata.IsRequired) labelText = labelText + " *";
labelText = labelText + ":";
TagBuilder tag = new TagBuilder("label");
tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
tag.SetInnerText(labelText);
return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
}
}
To use it:
<%:Html.SmartLabelFor(m => m.FirstName)%>
It will render:
<label for="FirstName">First Name:</label>
Or if you uncomment the required field related *
<label for="FirstName">First Name *:</label>
Just write a regular <label> element in plain HTML:
<label>My Label:</label>
If you want to output the for="" attribute and accurately render the control's name then use this extension method:
using System;
using System.Linq.Expressions;
using System.Web.Mvc;
namespace MvcLibrary.Extensions
{
public static class HtmlExtensions
{
public static MvcHtmlString FieldIdFor<TModel, TValue>(
this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
{
string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
string inputFieldId = html.ViewContext.ViewData.
TemplateInfo.GetFullHtmlFieldId(htmlFieldName);
return MvcHtmlString.Create(inputFieldId);
}
}
}
Then you can use in your view like so:
<label for="<%= Html.FieldIdFor(m => m.EmailAddress) %>">E-mail address:</label>
<%= Html.TextBoxFor(m => m.EmailAddress) %>
The other posts cover different approaches, they are all equally valid, which one you go for is matter of personal preference. I personally prefer writing the <label> as plain HTML as it gives designers more flexibility with changing markup, adding extra attributes such as CSS classes etc. Also I feel the label text is a view concern and shouldn't be decorated on the ViewModel class, but that's just my personal opinion/preference, I know some people here will disagree with me and that's fine :-)
You can create a String.ascx in DisplayTemplates folder and provide your own implementation. Refer to the Overriding Templates section of the following article.
http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html
You could do this using MVC 2 (if possible) if you pass a custom ViewModel to the view.
using System.ComponentModel;
public class PersonViewModel
{
public PersonViewModel(string name)
{
this.Name = name;
}
[DisplayName(".Display Anything You Like Here.")]
public string Name { get; set; }
I think the best approach would be writing your own helper method that renders what you like. You can overload the existing method or simply create a new method.