Добавление html-страниц в LabelFor - MVC 3 - PullRequest
7 голосов
/ 19 октября 2011

У меня сложная форма, которая должна использоваться как пользователями javascript, так и не-javascript.Мое приложение .NET MVC 3.

Форма содержит множество полей, которые необходимо заполнить, если они отвечают определенным образом на предыдущий вопрос.С включенным JavaScript, я могу показать или скрыть соответствующий вопрос на основе взаимодействия с пользователем.Без javascript я хотел бы добавить больше деталей к самой метке вопроса, потому что по умолчанию отображаются все вопросы (очень похоже на заполнение бумажной версии формы).

В идеале я хотел бы, чтобы меткабыть примерно таким:

<label><span class="non-js">If you were a smoker, when</span><span class="js">When</span> did you stop smoking?</label>

Таким образом, я могу отключить соответствующий текст в CSS (я надеюсь, что программа чтения с экрана может справиться с этим).

Таким образом, пользователи javascript получают:

When did you stop smoking?

и пользователи, не поддерживающие javascript, получают:

If you were a smoker, when did you stop smoking?

Мой вопрос заключается в том, как мне поступить, поскольку помощники LabelFor не допускают использование html в строке.

Обновление

Извините, я забыл одну важную информацию, поскольку мой ярлык в настоящее время заполнен [Display (Name = "Когда вы бросили курить?")]аннотация в модели.В идеале я хотел бы сохранить это здесь и иметь что-то вроде:

[Display(JS = "When", NonJS = "If you were a smoker, when", Both="did you stop smoking?")]

Возможно ли это?

Обновление 2

Хорошо, вот что у меня так далеко.Это мой атрибут:

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);
    }
}

К сожалению, я застрял, так как это отображается в незашифрованном виде на экране.то есть на самом деле это выглядит так:

<span class="non-js">If you were a smoker, when</span><span class="js">When</span> did you stop smoking?

Есть ли способ изменить свойство метаданных displayName, чтобы справиться с этим?

Обновление 3 и решение

С помощью ответов и http://weblogs.asp.net/imranbaloch/archive/2010/07/03/asp-net-mvc-labelfor-helper-with-htmlattributes.aspx мне удалось получить решения, которые мне нужны:

Мой атрибут:

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;
    }
}

Мой помощник:

    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));
    }

Работа выполнена (в конце концов!) Спасибо всем за помощь!

Ответы [ 2 ]

5 голосов
/ 27 октября 2011

Ваша текущая проблема заключается в том, как работает LabelFor. Это декомпилированный исходный код для LabelFor (из MVC2. Фактический источник, вероятно, более приятный и доступен для загрузки бесплатно):

    public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
    {
      return LabelExtensions.LabelHelper((HtmlHelper) html, ModelMetadata.FromLambdaExpression<TModel, TValue>(expression, html.ViewData), ExpressionHelper.GetExpressionText((LambdaExpression) expression));
    }

    internal static MvcHtmlString LabelHelper(HtmlHelper html, ModelMetadata metadata, string htmlFieldName)
    {
      string str = metadata.DisplayName;
      if (str == null)
      {
        string propertyName = metadata.PropertyName;
        if (propertyName == null)
          str = Enumerable.Last<string>((IEnumerable<string>) htmlFieldName.Split(new char[1]
          {
            '.'
          }));
        else
          str = propertyName;
      }
      string innerText = str;
      if (string.IsNullOrEmpty(innerText))
        return MvcHtmlString.Empty;
      TagBuilder tagBuilder = new TagBuilder("label");
      tagBuilder.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
      tagBuilder.SetInnerText(innerText);
      return tagBuilder.ToMvcHtmlString(TagRenderMode.Normal);
    }
  }

Вы можете скопировать этот код, изменить имя метода и изменить вторую последнюю строку кода следующим образом:

tagBuilder.InnerHtml(innerText);

И у вас будет рабочее решение, которое не выходит за рамки вашего HTML.

5 голосов
/ 19 октября 2011

Вы можете написать собственное расширение LabelFor для Html.Я бы порекомендовал это, поскольку вы могли бы передавать текст js и non-js в качестве параметров вместо того, чтобы писать HTML снова и снова.Вот основной помощник типа Label:

using System;
namespace MvcApplication1.Helpers
{
      public class LabelHelper
      {
           public static string LabelJsNonJs(this HtmlHelper helper, string target, string nonJs, string js, string commonText)
           {
                return String.Format("<label for='{0}'><span class='non-js'>{1}</span><span class='js'>{2}</span>{3}</label>", target, nonJs, js, commonText);
           }
      }
}

Вы можете использовать это в своих представлениях, добавив использование для своего пространства имен MvcApplication1.Helpers.

См. http://weblogs.asp.net/imranbaloch/archive/2010/07/03/asp-net-mvc-labelfor-helper-with-htmlattributes.aspx для получения дополнительной информациипо созданию помощника типа LabelFor (немного сложнее, и у меня не так много времени).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...