【问题标题】:tooltip for each item in dynamically generated @html.dropdownfor control in mvc3动态生成的每个项目的工具提示 @html.dropdownfor mvc3 中的控件
【发布时间】:2015-01-25 19:09:31
【问题描述】:

我正在使用 Razor c# 在 MVC 3 中开发 Web 项目。

我使用了@Html.DropDownListFor 动态显示项目。我想为@Html.DropDownListFor 的每个项目设置工具提示。

我的代码如下

@Html.DropDownListFor(m => m.Type, new SelectList(Model.Types, "Value", "Text", Model.Type), 
new { @class = "Type"})

【问题讨论】:

  • Html.DropDownListFor(m => m.Type, new SelectList(Model.Types, "Value", "Text", Model.Type), new { class= "Type" , @Title = "toolTip"}) 我添加了 title 属性。但我在所有项目中都获得了相同的标题。我需要不同的类型
  • 这只会将工具提示提示添加到select。为了添加工具提示,您需要创建自己的 html 帮助程序来构建 html 或使用 jquery。
  • 这里如何使用jquery?
  • 您将title 属性添加到每个选项并设置其值。您希望工具提示文本是什么?
  • @Rem - 请检查我的答案。我认为这与斯蒂芬在他上次评论中的建议一致。

标签: jquery html asp.net-mvc tooltip dropdownlistfor


【解决方案1】:

我对这个问题感到好奇,所以只是试图实现它。我创建了一个简单的示例,并让它在每个选择项悬停时显示不同的工具提示。

注意:我不是 JS 方面的专家,不确定这是否是一种理想的方式。

这是我的示例代码:

MyController.cs

    public ActionResult LoadCountries()
    {
        List<SelectListItem> li = new List<SelectListItem>();
        li.Add(new SelectListItem { Text = "Select", Value = "0" });
        li.Add(new SelectListItem { Text = "India", Value = "1" });
        li.Add(new SelectListItem { Text = "Srilanka", Value = "2" });
        li.Add(new SelectListItem { Text = "China", Value = "3" });
        li.Add(new SelectListItem { Text = "Austrila", Value = "4" });
        li.Add(new SelectListItem { Text = "USA", Value = "5" });
        li.Add(new SelectListItem { Text = "UK", Value = "6" });
        ViewData["country"] = li;
        return View();
    }

LoadCountries.cshtml

<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="~/Scripts/TooltipDefinition.js"></script>

@{
    ViewBag.Title = "title";
}

<h2>Just For Demo</h2>

@using (Html.BeginForm())
{
    @Html.DropDownList("Countries", ViewData["country"] as List<SelectListItem>)
}

<h2 id="tooltipData"></h2>

<script type="text/javascript">

    $("#Countries > option").each(function () {
        var item = $(this).text();

        if (item !== "Select") {
            var tooltipText = MouseHoverText(item);
            $(this).attr("title", tooltipText);
        }
    });

</script>

TooltipDefinition.js

var MouseHoverText = function(id) {
    switch (id) {
        case "India":
            return "You have selected India - A country full of opportunities.";
        break;
    case "Srilanka":
        return "You have selected Srilanka - God's own country.";
        break;
    default:
        return "You have selected " + id;
    }
};

我想我没有做任何与你尝试不同的事情。我正在捕获所有选择的项目并在加载项目时附加标题属性。工具提示文本来自 JS 文件。您可能可以通过 Model 传递它。

分享,因为它可能很适合您的需要。

【讨论】:

    【解决方案2】:

    我也做过类似的事情

    我声明了两个类,一个用于模型,一个用于保存下拉列表的每个选项标签的值

    public Class Report
    {
      public ReportName {get; set;}
      public IList<ReportSummaryModel> AvailableReports {get; set;}
    }
    
    public class ReportSummaryModel
    {
      public ReportActualName {get; set;}
      public ReportClassName {get; set;}    
      public TextField {get; set;}
      public ValueField {get; set;}
    }
    

    我想将 ReportActualName 和 ReportClassName 输出到下拉列表的选项标签上,这些值因每个选项而异。

    所以我在下面写了 HTML 辅助函数

    public static MvcHtmlString DropDownList<TPageModel, TSelectListModel, TProperty>(this HtmlHelper<TPageModel> htmlHelper, 
      Expression<Func<TPageModel, TProperty>> expression, IEnumerable<TSelectListModel> selectList, Expression<Func<TSelectListModel, TProperty>> textField, 
      Expression<Func<TSelectListModel, TProperty>> valueField, string optionLabel, IDictionary<string, Expression<Func<TSelectListModel, TProperty>>> optionsAttributes)
    

    下面会提到实际的函数调用

    @Html.DropDownList(x => x.ReportName, 
    Model.AvailableReports, 
    x => x.TextField, 
    x => x.ValueField, 
    "-- Select --", 
    new Dictionary<string, Expression<Func<ReportSummaryModel, object>>>{ {"data-name", x => x.ReportActualName}, {"data-class", x => x.ReportClassName}})
    

    其余的效用函数如下所述

    public static MvcHtmlString DropDownList<TPageModel, TSelectListModel, TProperty>(this HtmlHelper<TPageModel> htmlHelper, Expression<Func<TPageModel, TProperty>> expression, IEnumerable<TSelectListModel> selectList, Expression<Func<TSelectListModel, TProperty>> textField, Expression<Func<TSelectListModel, TProperty>> valueField, string optionLabel, IDictionary<string, Expression<Func<TSelectListModel, TProperty>>> optionsAttributes)
            {
                string name = ExpressionHelper.GetExpressionText(expression);
                string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
                string defaultValue = string.Empty;
                ModelState modelState;
                if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState))
                {
                    if (modelState.Value != null)
                    {
                        defaultValue = (string)modelState.Value.ConvertTo(typeof(string), null /* culture */);
                    }
                }
                var listItemBuilder = new StringBuilder();
                // Make optionLabel the first item that gets rendered.
                if (optionLabel != null)
                {
                    listItemBuilder.AppendLine(ListItemToOption(optionLabel, string.Empty, false, null));
                }
                /* Loop through each options
                 * Convert each ListItem to an <option> tag */
                foreach (var listItem in selectList)
                {
                    string text = listItem.GetType()
                                          .GetProperties()
                                          .Single(p => p.Name.Equals(ClassHelper.PropertyName(textField)))
                                          .GetValue(listItem, null)
                                          .ToString();
                    string value = listItem.GetType()
                                           .GetProperties()
                                           .Single(p => p.Name.Equals(ClassHelper.PropertyName(valueField)))
                                           .GetValue(listItem, null)
                                           .ToString();
                    bool isSelected = value.Equals(defaultValue);
                    var htmlAttributes = new Dictionary<string, string>();
                    foreach (var option in optionsAttributes)
                    {
                        string propertyName = ClassHelper.PropertyName(option.Value);
                        htmlAttributes.Add(option.Key, listItem.GetType()
                                                                 .GetProperties()
                                                                 .Single(p => p.Name.Equals(propertyName))
                                                                 .GetValue(listItem, null)
                                                                 .ToString());
                    }
                    listItemBuilder.AppendLine(ListItemToOption(text, value, isSelected, htmlAttributes));
                }
                var tagBuilder = new TagBuilder("select")
                {
                    InnerHtml = listItemBuilder.ToString()
                };
                tagBuilder.MergeAttribute("name", fullName, true /* replaceExisting */);
                return new MvcHtmlString(tagBuilder.ToString(TagRenderMode.Normal));
            }
    
    //Private method copied from mvc built in helper to generate option attribute
    
     internal static string ListItemToOption(string text, string value, bool isSelected, IDictionary<string, string> htmlAttributes)
            {
                var builder = new TagBuilder("option")
                {
                    InnerHtml = HttpUtility.HtmlEncode(text)
                };
                if (value != null)
                {
                    builder.Attributes["value"] = value;
                }
                if (isSelected)
                {
                    builder.Attributes["selected"] = "selected";
                }
                if (htmlAttributes != null)
                {
                    builder.MergeAttributes(htmlAttributes);
                }
    
                return builder.ToString(TagRenderMode.Normal);
            }
    
    
    //Utility function to get property name
    
    public class ClassHelper
        {
            public static string PropertyName<TModel, TProperty>(Expression<Func<TModel, TProperty>> expression)
            {
                var body = expression.Body as MemberExpression;
                if (body == null)
                {
                    body = ((UnaryExpression)expression.Body).Operand as MemberExpression;
                }
                return body.Member.Name;
            }
        }
    

    输出是

    <select name="ReportName">
     <option>--Select--</option>
     <option value="1" data-name="NameA" data-class="classA">A</option>                  
        <option value="2" data-name="NameB" data-class="classB">B</option>                  
        <option value="3" data-name="NameC" data-class="classC">C</option>                  
        <option value="4" data-name="NameD" data-class="classD">D</option>                  
    </select>

    【讨论】:

    • 一个&lt;select&gt; 不绑定到属性并且不回发任何内容。不是很有用!如果您想开始编写自己的 html 帮助程序,请花一些时间研究 MVC 源代码
    • 我看到您现在更改了输出以添加name 属性!
    【解决方案3】:

    你不能开箱即用。一种方法是使用 answer 中描述的 js

    另一个机会是创建您自己的类型,如SelectListItem,但使用Title 属性并为您的类型创建EditorTemplate。对于这个变体,我提供了一些代码:

    您的模板视图模型:

    using System.Collections.Generic;
    using System.Web.Mvc;
    
    namespace Templates.ViewModels
    {
        public class SelectListItemWithTitle: SelectListItem
        {
            public string Title { get; set; }
        }
    
        public class SelectListWithTitle
        {
            public SelectListWithTitle(IEnumerable<SelectListItemWithTitle> items)
            {
                Items = items;
            }
            public IEnumerable<SelectListItemWithTitle> Items { get; set; }
        }
    }
    

    您的 EditorTemplate 应放置在 /Views/Shared/EditorTemplates 中,名称为 SelectListWithTitle.cshtml

    @model Templates.ViewModels.SelectListWithTitle
    
    @{
        Layout = null;
    }
    
    <select id="@ViewData.TemplateInfo.HtmlFieldPrefix" name="@ViewData.TemplateInfo.HtmlFieldPrefix">
        @foreach (var item in Model.Items)
        {
            <option value="@item.Value" selected="@item.Selected" title="@item.Title">@item.Text</option>
        }
    </select>
    

    你的 ViewModel 是这样的:

    public class ViewModel
    {
        public SelectListWithTitle Meal { get; set; }
    }
    

    你的控制器:

    public ActionResult Index()
    {
        List<SelectListItemWithTitle> selectListItemsWithTitle = new List<SelectListItemWithTitle>();
        selectListItemsWithTitle.Add(new SelectListItemWithTitle { Text = "Apple", Value = "0", Title = "Fresh" });
        selectListItemsWithTitle.Add(new SelectListItemWithTitle { Text = "Orange", Value = "1", Title = "Jussy" });
        selectListItemsWithTitle.Add(new SelectListItemWithTitle { Text = "Banana", Value = "2", Title = "Yellow", Selected = true });
        selectListItemsWithTitle.Add(new SelectListItemWithTitle { Text = "Vodka", Value = "3", Title = "Russian" });
        selectListItemsWithTitle.Add(new SelectListItemWithTitle { Text = "Beer", Value = "4", Title = "Cold" });
    
        SelectListWithTitle sl = new SelectListWithTitle(selectListItemsWithTitle);
    
        ViewModel model = new ViewModel
        {
            Meal = sl
        };
        ViewData.Model = model;
    
        return View();
    }
    

    还有你的浏览指数:

    @model MvcApplication1.Models.ViewModel
    
    @Html.EditorFor(m => m.Meal)
    

    不要忘记更改命名空间。

    【讨论】:

    • 创建一个EditorTemplate 是行不通的。您需要创建一个自定义 Html Helper。
    • @StephenMuecke 为什么不使用@Html.EditorFor 而不是@Html.DropDownListFor
    • 因为EditorTemplate 不允许您访问和更改为每个选项生成的html(即添加title 属性。@Html.DropDownListFor()` 方法生成基于在IEnumerable&lt;SelectListItem&gt; 上,如果您替换自己的类型,它将无法工作,并且无论如何它都不会理解Title 属性
    • @StephenMuecke 我们没有得到对方,我稍后会在回答中提供我的意思。
    • 祝你好运。我认为这将是很久很久以后。 :) Darin 在您的第二个链接中的回答与该问题有什么关系 - 那只是在 EditorTemplate 内使用 DropDownList 而不是直接在视图中。
    猜你喜欢
    • 2012-01-16
    • 1970-01-01
    • 2019-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多