2

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

为了提供上下文,应用程序记录Runs. 每个都Run必须有一个Route与之关联的。一个Route含义,用户跑到哪里。

当用户输入 a时,选项会显示Route他们的列表,但数据库需要验证。RoutesautocompleteRouteID

为了弥补这一点,我将其存储RouteIDHiddenForHtmlHelper 中。当用户从 中选择路线时autocomplete,将HiddenFor被分配。

我的问题是
如果用户输入 的全名Route,而不是从autocomplete列表中选择它或输入一个Route不存在的,HiddenFor将不会被分配。发生这种情况时,我必须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);
}
4

2 回答 2

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/

于 2012-06-20T18:32:00.127 回答
1

好吧,经过大量的摆弄,我想出了以下实现:

下面的代码是一个HtmlHelper被调用的@Html.AutocompleteWithHiddenFor. HtmlHelper 将创建一个inputHTML 元素,该元素具有data-autocomplete-url基于controlleraction传入的属性。

如果input元素需要 avalue那么您也可以将其传入。HiddenFor将为Model传入的属性创建A ,并且ValidationMessageFor还将为 the 创建Model

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

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

自动完成助手类

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) 
于 2012-06-22T22:53:31.737 回答