I have a complex form that should be used by both javascript and non-javascript users. My application is .NET MVC 3.
There are many fields on the form that need to be completed if they answer in a certain way to the previous question. If javascript is enabled, I can show or hide the corresponding question based on user interaction. Without javascript, I would like to add more detailed information to the question label itself, because by default all questions are displayed (like filling out a paper version of the form).
Ideally, I would like the label to be something like:
<label><span class="non-js">If you were a smoker, when</span><span class="js">When</span> did you stop smoking?</label>
That way I can turn off the corresponding text in CSS (I hope the firmware can handle this).
So javascript users get:
When did you stop smoking?
and non-javascript users get:
If you were a smoker, when did you stop smoking?
My question is how I will deal with this, since LabelFor helpers do not allow html in line.
Update
Sorry, I forgot one key bit of information, because my shortcut is currently filling out the annotation in the model [Display (Name = "When did you stop smoking?")]. Idelly I would like to keep this here and have something like:
[Display(JS = "When", NonJS = "If you were a smoker, when", Both="did you stop smoking?")]
Is it possible?
Update 2
Well, thatβs what I have so far. This is my attribute:
public class MultipleDisplayNameAttribute : Attribute, IMetadataAware { public string CustomerDisplayName { get; set; } public string CustomerJSAlternative { get; set; } public string CustomerNonJSAlternative { get; set; } public void OnMetadataCreated(ModelMetadata metadata) { string jsPart; string nonJsPart; jsPart = (CustomerJSAlternative != null) ? String.Format("<span class='spnJs'>{0}</span>", CustomerJSAlternative) : ""; nonJsPart = (CustomerNonJSAlternative != null) ? String.Format("<span class='spnNonJs'>{0}</span>", CustomerNonJSAlternative) : ""; metadata.DisplayName = String.Format("{0}{1}{2}", jsPart, nonJsPart, CustomerDisplayName); } }
Unfortunately, I'm stuck right now, as it is displayed on the screen without restrictions. that is, on the screen it looks like this:
<span class="non-js">If you were a smoker, when</span><span class="js">When</span> did you stop smoking?
Is there a way to change the displayName metadata property to handle this?
Update 3 and solution
Using answers and http://weblogs.asp.net/imranbaloch/archive/2010/07/03/asp-net-mvc-labelfor-helper-with-htmlattributes.aspx I was able to get the solutions that I got after:
My attribute:
public class MultipleDisplayNameAttribute : Attribute, IMetadataAware { public string CustomerDisplayName { get; set; } public string CustomerJSAlternative { get; set; } public string CustomerNonJSAlternative { get; set; } public void OnMetadataCreated(ModelMetadata metadata) { metadata.AdditionalValues["JS"] = (CustomerJSAlternative != null) ? String.Format("<span class='spnJs'>{0}</span>", CustomerJSAlternative) : ""; metadata.AdditionalValues["NoJS"] = (CustomerNonJSAlternative != null) ? String.Format("<span class='spnNonJs'>{0}</span>", CustomerNonJSAlternative) : ""; metadata.DisplayName = CustomerDisplayName; } }
My helper:
public static MvcHtmlString JsAndNonJsCheckFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression) { var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData); HtmlString jsLabel = new HtmlString(""); HtmlString noJsLabel = new HtmlString(""); string htmlFieldName = ExpressionHelper.GetExpressionText(expression); string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last(); if (String.IsNullOrEmpty(labelText)) return MvcHtmlString.Empty; if(metadata.AdditionalValues.ContainsKey("JS")) jsLabel = new HtmlString((string)metadata.AdditionalValues["JS"]); if (metadata.AdditionalValues.ContainsKey("NoJS")) noJsLabel = new HtmlString((string)metadata.AdditionalValues["NoJS"]); TagBuilder tagBuilder = new TagBuilder("label"); tagBuilder.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName)); tagBuilder.InnerHtml = String.Format("{0}{1}{2}", jsLabel, noJsLabel, labelText); return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal)); }
The work is done (in the end!) Thanks for the help!