【问题标题】:Jquery ui autocomplete populating hidden field with IDJquery ui自动完成填充带有ID​​的隐藏字段
【发布时间】:2011-08-18 21:38:55
【问题描述】:

我正在尝试让自动完成插件在一个文本框中填充大学名称,在另一个文本框中填充大学代码。下面的代码返回结果并填充大学名称文本框,但我不知道如何填充另一个输入。

我试过关注这个example,但遇到了问题,甚至调用了webmethod。一件奇怪的事情是,似乎在自动完成附加到用户键入的文本框之前调用了 ajax。不确定是什么触发了 js 调用自动完成方法。

我不得不将上面的部分与 jquery ui doc 结合使用 json (link) 进行自动完成。但我仍然不知道如何像第一个示例一样填充第二个输入。

有什么想法吗?

这里是 jquery 和 html

<script language="javascript" type="text/javascript">
    $(function () {
        $("#university").autocomplete({
            source: function (request, response) {
                $.ajax({
                    type: "POST",
                    url: "AutoComplete.asmx/GetUniversities",
                    dataType: "json",
                    data: "{ 'data': '" + request.term + "' }",
                    contentType: "application/json; charset=utf-8",
                    success: function (data) {
                        response($.map(data, function (item) {
                            return {                                    
                                value: item.Descr,
                                UnivCode: item.UnivCode

                            }                                
                        }));
                    }
                });
            } 
        });          
    });
</script>
<div class="ui-widget"> 
    <label for="university">University: </label> 
    <input id="university" type="text"/> 
    <label for="universityID">ID: </label> 
    <input id="universityID" type="text" /> 
</div> 

这是我的 .net 网络方法

using System;
using System.Web;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Collections.Generic;
using System.Web.Script.Services;
using System.Text;
using System.Data;

[ScriptService()]
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

public class AutoComplete : System.Web.Services.WebService
{

    [WebMethod]
    [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
    public List<University> GetUniversities(string data)
    {
        List<University> UniversityList = new List<University>();

        try
        {
            clsDataBase db = new clsDataBase();
            DataTable dt = new DataTable();
            StringBuilder sql = new StringBuilder();
            Dictionary<string, object> parms = new Dictionary<string, object>();

            sql.Append(" SELECT univ_code ");
            sql.Append(" , INITCAP(univ_desc) AS descr ");
            sql.Append(" FROM lk_university ");
            sql.Append(" WHERE UPPER(univ_desc) LIKE UPPER(?) ");
            sql.Append(" ORDER BY univ_desc  ");
            parms.Add("university", "%" + data + "%");

            dt = db.executeParmQuery(sql.ToString(), parms);
            DataView dv = new DataView(dt);


            ArrayList filteredList = new ArrayList();

            foreach (DataRowView drv in dv)
            {
                University university = new University();
                university.UnivCode= drv["univ_code"].ToString();
                university.Descr = drv["descr"].ToString();

                UniversityList.Add(university);
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
            //return null;
        }
        //}
        return UniversityList;
    }


    public class University
    {        
        string _value;
        public string value
        {
            get { return _Descr + " (" + _UnivCode + ")"; }            
        }

        string _Descr;
        public string Descr
        {
            get { return _Descr; }
            set { _Descr = value; }
        }

        string _UnivCode;
        public string UnivCode
        {
            get { return _UnivCode; }
            set { _UnivCode = value; }
        }
    }
}

编辑

我能够通过添加选择事件来使其工作。在我之前的测试中,我把它放在那里,但是在错误的位置(最初嵌套在成功事件中)。还必须在设置值的成功事件中添加三行:item.Descr,Descr:item.Descr,和UnivCode:item.UnivCode。我不太明白这些引用的是什么或它们在做什么,因为输入的实际设置是在选择事件中完成的,在该事件中我指定了输入的实际 id ($('#university').val(ui .item.Descr);),但这是使代码正常工作所必需的。

这是工作 jquery,没有对 html 或 .net 代码进行任何其他更改。

<script language="javascript" type="text/javascript">
    $(function () {
        $("#university").autocomplete({
            source: function (request, response) {
                $.ajax({
                    type: "POST",
                    url: "AutoComplete.asmx/GetUniversities",
                    dataType: "json",
                    data: "{ 'data': '" + request.term + "' }",
                    contentType: "application/json; charset=utf-8",
                    success: function (data) {
                        response($.map(data, function (item) {
                            return {
                                value: item.Descr,
                                Descr: item.Descr,
                                UnivCode: item.UnivCode
                            }
                        }));
                    }
                });
            },
            select: function (event, ui) {
                $('#university').val(ui.item.Descr);
                $('#universityID').val(ui.item.UnivCode);                    
                return false;
            }
        });
    });

【问题讨论】:

    标签: jquery asp.net json jquery-ui autocomplete


    【解决方案1】:

    我能够通过添加选择事件来使其工作。在我之前的测试中,我把它放在那里,但是在错误的位置(最初嵌套在成功事件中)。还必须在设置值的成功事件中添加三行:item.Descr,Descr:item.Descr,和UnivCode:item.UnivCode。我不太明白这些引用的是什么或它们在做什么,因为输入的实际设置是在选择事件中完成的,在该事件中我指定了输入的实际 id ($('#university').val(ui .item.Descr);),但这是使代码正常工作所必需的。

    这是工作 jquery,没有对 html 或 .net 代码进行任何其他更改。

    $(function () {
        $("#university").autocomplete({
            source: function (request, response) {
                $.ajax({
                    type: "POST",
                    url: "AutoComplete.asmx/GetUniversities",
                    dataType: "json",
                    data: "{ 'data': '" + request.term + "' }",
                    contentType: "application/json; charset=utf-8",
                    success: function (data) {
                        response($.map(data, function (item) {
                            return {
                                value: item.Descr,
                                Descr: item.Descr,
                                UnivCode: item.UnivCode
                            }
                        }));
                    }
                });
            },
            select: function (event, ui) {
                $('#university').val(ui.item.Descr);
                $('#universityID').val(ui.item.UnivCode);                    
                return false;
            }
        });
    });
    

    【讨论】:

      【解决方案2】:

      我在使用 MVC 时经历过这种痛苦,您返回的对象需要有一个标签属性(显示在下拉列表中)和一个值属性(实际选择值 - UnivCode)。

      它的关键是在您的自动完成框上定义了一个选择方法,该方法接受 2 个参数(例如 select: function(e, ui){ ... do stuff ...; return false; })。这里的技巧是 return false 以防止 jQuery 运行默认事件处理程序。

      然后你可以使用 ui.item.label 获取显示值,使用 ui.item.value 获取代码。

      我使用了一个单独的方法来接受 ui.item,然后将值写入隐藏的输入。

      如果我能把我的代码放在一起,我会发布一个例子。

      示例:- 此示例使用一个名为 Autocomp1_display 的文本框,自动完成功能附加到该文本框。 displayItem 方法然后将选中项的显示值写入此文本框,并将选中的值放入隐藏跨度中。

      $j("#Autocomp1_display").autocomplete({
      source: function(request, response){
          $j.ajaxSetup({cache: false});
          $j.ajax({
              url: "AutoComplete.asmx/GetUniversities"
                  type: "GET",
              data: request,
              dataType: "json",
              success: function (data) {
                  request.term="";
                  response(data);
              }
          });
      },
      cache: false,
      select: function(e, ui){
          displayItem("Autocomp1", ui.item);
          Autocomp1_HasSelections = true;
          setAutocompleteState("Autocomp1_display", Autocomp1_IsMultiSelect, Autocomp1_HasSelections);
          $j('#Autocomp1').change();
          return false;
      },
      focus: function(event, ui){
          if (ui.item.label){
              $j(this).val(ui.item.label);
          } else {
              $j(this).val(ui.item.value);
          }
          return false;
      }
      });
      

      select 事件使用如下 displayItem 方法

      //Function to write the entries into the text box
      function displayItem(target, dataObject) {
          var displayValue = dataObject.label.replace('\n','');
      
          var existingSpan = false;
      
          existingSpan = document.getElementById("span_" + displayValue);
      
          if (!existingSpan) {
              var span = $j("<span>").text(displayValue); //Create a new span tag to display the selected value
              span.attr({ id: "span_" + dataObject.value });
              var hiddenFld = $j("<input>").attr({ type: "hidden" }).val(dataObject.value); //Create a div object to store the code value
              hiddenFld.addClass(target + "IdField").css("visibility", "hidden").css("height", 0).attr({ id: target, name: target }); //Format the div
              var a = $j("<a>").addClass(target + "remove").attr({
                  href: "javascript:",
                  title: "Remove " + displayValue
              }).text("x").appendTo(span); //Define the "x" to remove the span
      
              hiddenFld.appendTo(span); //Append the div to the span
              span.insertBefore("#" + target + "_display"); //Insert span before the concealed text box
              $j("#" + target).attr({ value: dataObject.value }); //Store the ID value related to the selected item
              $j("#" + target + "_display").val("").css("top", 2); //Store the ID value related to the selected item
              //$j("#" + target + "_display").flushCache(); //Flush the cache for the autocomplete control
          } else {
              alert("This item has already been selected");
          }
      }
      

      setAutocompleteState 方法:-

      function setAutocompleteState(targetName, IsMultiSelect, HasSelections) {
          if (!IsMultiSelect && HasSelections) {
              $j("#" + targetName).autocomplete("option", "disabled", true);
          } else {
              $j("#" + targetName).autocomplete("option", "disabled", false);
          }
      }
      

      isMultiSelect 和 HasSelections 定义是否应该启用自动完成功能,而 targetName 只是已经“自动完成”的文本框的 ID

      【讨论】:

      • 这是基于本教程/文章here
      • 我能够解决我的问题(请参阅上面的编辑),但有兴趣尝试让您的 facebook 样式添加的字段正常工作。我更新了我的 .net 对象以返回标签和值,但没有在网站上获得任何结果。在名为 .net webmethod 的 AutoComp1_display 文本框中键入返回结果(我正在通过提琴手查看所有流量),但文本框下没有显示任何结果。当我键入时,会显示一个大约 5px 高的蓝色小 div,但其中没有值。
      • 对您的代码有其他问题。在你的最后,它是否像上面写的那样工作?您在哪里定义 setAutocompleteState 以及它有什么作用?您声明了 Autocom1_HasSelections,但没有声明 Autocom1_IsMultiSelect,这些属性和上述方法是否超出了获取自动完成以填充隐藏字段的目标范围?
      • 最后一件事。我想做的与您在示例中所做的不同是将所选值作为跨度附加到输入文本框下方的 div 中,其中每个值都将位于其自己的行上。除了将 div 的 id 发送到显示项函数而不是输入文本框之外,这是否需要对您的代码进行任何其他更改?
      • Jarek,这段代码是一个更大的系统的一部分,并且部分已经被通用编写以允许在一个页面上进行多个自动完成,而实际的自动完成控件是在运行时使用 MVC Html 扩展方法呈现的。 setAutocomplete 方法与 displayItem 在同一个文件中定义,只是将自动完成设置为禁用或不禁用(请参阅答案中的编辑)。
      【解决方案3】:

      与自动完成控件一起使用的样式

      .acarea { padding:3px 3px 0; margin:0 auto; background-color:#fff; cursor:text; }
      .acarea div {border:1px solid #aaa; }
      .acarea input {border:0px; display:inline;}
      .acarea span { display:block; width:auto; margin:0 3px 3px 0; padding:3px 20px 4px 8px; position:relative; float:left; text-indent:0; background-color:#eee; border:1px solid #333; -moz-border-radius:7px; -webkit-border-radius:7px; border-radius:7px; color:#333; font:normal 11px Verdana, Sans-serif; }
      .acarea span a { position:absolute; right:8px; top:2px; color:#666; font:bold 12px Verdana, Sans-serif; text-decoration:none; }
      .acarea span a:hover { color:#ff0000; }
      .ui-menu .ui-menu-item { white-space:nowrap; padding:0 10px 0 0; }
      

      自动完成控件的库函数

      //Function to write the entries into the text box
      function displayItem(target, dataObject) {
          var displayValue = dataObject.label.replace('\n','');
      
          var existingSpan = false;
      
          existingSpan = document.getElementById("span_" + displayValue);
      
          if (!existingSpan) {
              var span = $j("<span>").text(displayValue); //Create a new span tag to display the selected value
              span.attr({ id: "span_" + dataObject.value });
              var hiddenFld = $j("<input>").attr({ type: "hidden" }).val(dataObject.value); //Create a div object to store the code value
              hiddenFld.addClass(target + "IdField").css("visibility", "hidden").css("height", 0).attr({ id: target, name: target }); //Format the div
              var a = $j("<a>").addClass(target + "remove").attr({
                  href: "javascript:",
                  title: "Remove " + displayValue
              }).text("x").appendTo(span); //Define the "x" to remove the span
      
              hiddenFld.appendTo(span); //Append the div to the span
              span.insertBefore("#" + target + "_display"); //Insert span before the concealed text box
              $j("#" + target).attr({ value: dataObject.value }); //Store the ID value related to the selected item
              $j("#" + target + "_display").val("").css("top", 2); //Store the ID value related to the selected item
              //$j("#" + target + "_display").flushCache(); //Flush the cache for the autocomplete control
          } else {
              alert("This item has already been selected");
          }
      }
      
      //function to load the existing data as entries
      //targetName is the id of the control being rendered
      //existingEntries is an array of objects that contain a label and value property (at least!!)
      function loadItems(targetName, existingEntries){
          for (i=0;i<existingEntries.length;i++) {
              displayItem(targetName, existingEntries[i]);
          } //End of for loop
      } //End of function
      
      function setAutocompleteState(targetName, IsMultiSelect, HasSelections) {
          if (!IsMultiSelect && HasSelections) {
              $j("#" + targetName).autocomplete("option", "disabled", true);
          } else {
              $j("#" + targetName).autocomplete("option", "disabled", false);
          }
      }
      

      MVC 扩展方法渲染的代码

      <script language="javascript">
      var Autocomp1_existingEntries = null;
      var Autocomp1_IsMultiSelect = false;
      var Autocomp1_HasSelections = false;
      </script>
      
      <div class="acarea" id="Autocomp1_acarea"><div class="ui-helper-clearfix"><input id="Autocomp1_display" type="text" /></div></div>
      
      <script type="text/javascript" language="javascript">
      $j(document).ready(function () {
      $j("#Autocomp1_display").autocomplete({
      source: function(request, response){
          $j.ajaxSetup({cache: false});
          $j.ajax({
          url: "AutoComplete.asmx/GetUniversities",
          type: "GET",
          data: request,
          dataType: "json",
          success: function (data) {
                  request.term="";
                  response(data);
              }
          });
      },
      cache: false,
      select: function(e, ui){
          displayItem("Autocomp1", ui.item);
          Autocomp1_HasSelections = true;
          setAutocompleteState("Autocomp1_display", Autocomp1_IsMultiSelect, Autocomp1_HasSelections);
          $j('#Autocomp1').change();
          return false;
      },
      focus: function(event, ui){
          if (ui.item.label){
              $j(this).val(ui.item.label);
          } else {
              $j(this).val(ui.item.value);
          }
          return false;
      }});
      })
      
      if (Autocomp1_existingEntries != null){
          loadItems("Autocomp1", Autocomp1_existingEntries);
          Autocomp1_HasSelections = true;
          setAutocompleteState("Autocomp1_display", Autocomp1_IsMultiSelect, Autocomp1_HasSelections);
      }
      
      $j("#Autocomp1_acarea").click(function() {
          $j("#Autocomp1_display").focus();
      });
      
      $j(".Autocomp1remove", document.getElementById("Autocomp1_acarea")).live("click", function() {
          var spanDiv = $j(this).parent().parent();
          $j(this).parent().remove();
          Autocomp1_HasSelections = false;
          var Autocomp1_nodeCounter = 0;
      
          for (Autocomp1_nodeCounter = 0;Autocomp1_nodeCounter < spanDiv[0].childNodes.length; Autocomp1_nodeCounter++){
              if (spanDiv[0].childNodes[Autocomp1_nodeCounter].nodeName.toLowerCase()=="span"){
                  Autocomp1_HasSelections = true;     break;
              }
          }
      
          setAutocompleteState("Autocomp1_display", Autocomp1_IsMultiSelect, Autocomp1_HasSelections);
          if ($j("#Autocomp1_acarea span").length === 0) {
              $j("#Autocomp1_display").css("top", 0).val("");
          }
          $j('#Autocomp1').change();
      });
      

      这是我用于呈现自动完成控件并让它将所选值存储在 div 中的代码的整体。随意按摩它,让它为你工作。

      【讨论】:

        【解决方案4】:

        我编写了一个包装 JQuery UI 自动完成小部件的 Asp.Net WebControl。 WebControl 提供了一个属性:OnClientSelection,您可以将其设置为javascript 函数名称。 在幕后,它所做的正是您指定“选择”操作所做的。 我写了关于如何使用控件的文档。

        您可以在以下位置找到它:

        http://autocompletedotnet.codeplex.com/

        希望对你有帮助

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-10-25
          • 1970-01-01
          • 1970-01-01
          • 2011-02-01
          • 2010-11-15
          • 2018-05-03
          • 1970-01-01
          • 2017-05-17
          相关资源
          最近更新 更多