【问题标题】:MVC3 jQuery Autocomplete - User must select option, ID of option sent to serverMVC3 jQuery Autocomplete - 用户必须选择选项,发送到服务器的选项 ID
【发布时间】:2012-06-20 18:19:52
【问题描述】:

背景
目前在我的一个项目中,我在几个领域使用 jQuery autocomplete

为了提供上下文,应用程序记录Runs。每个Run 必须有一个与之关联的RouteRoute 意思是用户跑到哪里。

当用户输入Route 时,autocomplete 选项会显示他们的Routes 列表,但数据库需要RouteID 进行验证。

为了弥补这一点,我将RouteID 存储在HiddenFor HtmlHelper 中。当用户从autocomplete 中选择路由时,HiddenFor 被分配。

我的问题是什么
如果用户键入Route 的全名,而不是从autocomplete 列表中选择它或输入一个不存在的RouteHiddenFor 将不会被分配。发生这种情况时,我必须通过其名称找到 Route 并验证它是否存在于服务器上。

我希望不必为每个 autocomplete 创建此解决方法。

底线
有没有办法让autocomplete 更像select list?我希望用户别无选择,只能从autocomplete 列表中选择一个选项的文本,并将所选选项的值发送到服务器。

如果我必须坚持HiddenFor 方法,是否至少有一种方法可以强制用户从autocomplete 列表中选择一个选项?


下面是我目前使用的代码

标记

@Html.LabelFor(model => model.RouteID, "Route")
<input type="text" data-autocomplete-url="@Url.Action("../Route/GetRoutesByUser")" />
@Html.HiddenFor(m => m.RouteID)

jQuery

  $('*[data-autocomplete-url]')
    .each(function () {
        $(this).autocomplete({
            source: $(this).data("autocomplete-url"),
            minLength: 2,
            select: function (event, ui) {
                log(ui.item.id, ui.item.name);
            }
        });
    });

代码

public ActionResult GetRoutesByUser(string term)
{
    var routeList = db.Routes.Where(r => r.Name.Contains(term))
                    .Take(5)
                    .Select(r => new { id = r.RouteID, label = r.Name, name = "RouteID"});
    return Json(routeList, JsonRequestBehavior.AllowGet);
}

【问题讨论】:

    标签: jquery asp.net asp.net-mvc asp.net-mvc-3 jquery-ui-autocomplete


    【解决方案1】:

    我会为此使用change 事件,如果未选择项目,则清除input 的值:

    $('*[data-autocomplete-url]')
        .each(function () {
            $(this).autocomplete({
                source: $(this).data("autocomplete-url"),
                minLength: 2,
                select: function (event, ui) {
                    log(ui.item.id, ui.item.name);
                },
                change: function (event, ui) { 
                    if (!ui.item) { 
                        this.value = '';
                    } else {
                        // Populate your hidden input.
                    }
                }
            });
        });
    });
    

    示例: http://jsfiddle.net/urEzm/

    【讨论】:

    • 非常感谢您带领我参加变更活动。它在可用性方面肯定有所帮助。在玩了很多之后,我想出了我自己的实现,即这个过程的可重用 HtmlHelper。
    【解决方案2】:

    好吧,经过一番折腾,我想出了以下实现:

    下面的代码是一个名为@Html.AutocompleteWithHiddenForHtmlHelper。 HtmlHelper 将根据传入的controlleraction 创建一个带有data-autocomplete-url 属性的input HTML 元素。

    如果input 元素需要value,那么您也可以将其传入。将为传入的Model 属性创建一个HiddenFor,并为Model 创建一个ValidationMessageFor

    现在我要做的就是使用@Html.AutocompleteWithHiddenFor,并通过控制器和操作(可能还有值)传递我需要的任何表达式以获取自动完成功能并将ID传递给服务器文本

    jQuery

    $(function () {
        function log(id, name) {
            var hidden = $('#' + name);
            hidden.attr("value", id);
        }
    
        $('*[data-autocomplete-url]')
        .each(function () {
            $(this).autocomplete({
                source: $(this).data("autocomplete-url"),
                minLength: 2,
                select: function (event, ui) {
                    log(ui.item.id, ui.item.name);
                },
                change: function (event, ui) {
                    if (!ui.item) {
                        this.value = '';
                    } else {
                        log(ui.item.id, ui.item.name);
                    }
                }
            });
        });
    });
    

    AutocompleteHelper 类

    public static class AutocompleteHelper
    {
         /// <summary>
         /// Given a Model's property, a controller, and a method that belongs to that controller, 
         /// this function will create an input html element with a data-autocomplete-url property
         /// with the method the autocomplete will need to call the method. A HiddenFor will be
         /// created for the Model's property passed in, so the HiddenFor will be validated 
         /// and the html input will not.
         /// </summary>
          /// <returns></returns>
          public static MvcHtmlString AutocompleteWithHiddenFor<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression, string controllerName, string actionName, object value = null)
          {
              // Create the URL of the Autocomplete function
              string autocompleteUrl = UrlHelper.GenerateUrl(null, actionName,
                                                           controllerName,
                                                           null,
                                                           html.RouteCollection,
                                                           html.ViewContext.RequestContext,                                                              
                                                           includeImplicitMvcValues: true);
    
               // Create the input[type='text'] html element, that does 
               // not need to be aware of the model
               String textbox = "<input type='text' data-autocomplete-url='" + autocompleteUrl + "'";
    
               // However, it might need to be have a value already populated
               if (value != null)
               {
                   textbox += "value='" + value.ToString() + "'";
               }
    
               // close out the tag
               textbox += " />";
    
               // A validation message that will fire depending on any 
               // attributes placed on the property
               MvcHtmlString valid = html.ValidationMessageFor(expression);
    
               // The HiddenFor that will bind to the ID needed rather than 
               // the text received from the Autocomplete
               MvcHtmlString hidden = html.HiddenFor(expression);
    
               string both = textbox + " " + hidden + " " + valid;
               return MvcHtmlString.Create(both);
         }
    }
    

    查看

    @Html.LabelFor(model => model.RouteID, "Route")
    @Html.AutocompleteWithHiddenFor(model => model.RouteID, "Route", "GetRoutesByUser") 
    

    或者如果它需要一个

    @Html.LabelFor(model => model.Route, "Route")
    @Html.AutocompleteWithHiddenFor(model => model.RouteID, "Route", "GetRoutesByUser", @Model.RouteName) 
    

    【讨论】:

    • 记得添加:using System.Web.Mvc;并使用 System.Web.Mvc.Html;
    • 当然。否则它不会建立。我省略了它们,因为代码足够长。 Visual Studio 也会让您知道需要导入哪些库。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-07
    • 1970-01-01
    相关资源
    最近更新 更多