【问题标题】:Uncaught type error - cannot read property 'length' of undefined in JQuery Autocomplete未捕获的类型错误 - 无法读取 JQuery 自动完成中未定义的属性“长度”
【发布时间】:2014-02-16 23:31:44
【问题描述】:

我正在尝试实现 JQueryUI 的多值自动完成,但是我在主 JQuery 文件 (Jquery-2.1.0.js) 的第 464 行收到此错误。

我不确定这是否与下面的实现有关,或者与我在布局文件中引用 Jquery 和 Jquery UI 的方式有关。请告诉我:

布局中的文件引用

<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title - My ASP.NET MVC Application</title>
    <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
    <meta name="viewport" content="width=device-width" />

    <link href="~/Content/ui-lightness/jquery-ui-1.10.4.custom.min.css" rel="stylesheet" />
    <link href="~/Content/menuStyles.css" rel="stylesheet" />

    <script src="~/Scripts/jquery-2.1.0.min.js"></script>  
    <script src="~/Scripts/jquery-ui-1.10.4.min.js"></script>

    <script src="~/Scripts/menu_jquery.js"></script>  
    <link href="~/Content/demos.css" rel="stylesheet" />

    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
</head>

@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryui")
@RenderSection("scripts", required: false)

捆绑配置

 public static void RegisterBundles(BundleCollection bundles)
    {
        bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                    "~/Scripts/jquery-{version}.js"));

        bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
                    "~/Scripts/jquery-ui-{version}.js"));

        bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                    "~/Scripts/jquery.unobtrusive*",
                    "~/Scripts/jquery.validate*"));

        // Use the development version of Modernizr to develop with and learn from. Then, when you're
        // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
        bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
                    "~/Scripts/modernizr-*"));

        bundles.Add(new StyleBundle("~/Content/css").Include("~/Content/demos.css"));

        bundles.Add(new StyleBundle("~/Content/themes/base/css").Include(
                    "~/Content/themes/base/jquery.ui.core.css",
                    "~/Content/themes/base/jquery.ui.resizable.css",
                    "~/Content/themes/base/jquery.ui.selectable.css",
                    "~/Content/themes/base/jquery.ui.accordion.css",
                    "~/Content/themes/base/jquery.ui.autocomplete.css",
                    "~/Content/themes/base/jquery.ui.button.css",
                    "~/Content/themes/base/jquery.ui.dialog.css",
                    "~/Content/themes/base/jquery.ui.slider.css",
                    "~/Content/themes/base/jquery.ui.tabs.css",
                    "~/Content/themes/base/jquery.ui.datepicker.css",
                    "~/Content/themes/base/jquery.ui.progressbar.css",
                    "~/Content/themes/base/jquery.ui.theme.css"));
    }

这就是我实现自动完成插件的方式:

我把所有这些都放在一个局部视图中。

    <div class="ui-widget" style="text-align:left">
        <input id="city"/>
    </div> 

<style>
    .ui-autocomplete-loading {
        background: white url('Images/ui-anim_basic_16x16.gif') right center no-repeat;
    }
    #city { width: 25em; }
    </style>
<script>
    $(function () {

        debugger;
        $('#city').autocomplete({
            source: function (request, response) {
                $.ajax({
                    url: "Home/GetWhatever",
                    data: "{ 'pre':'" + request.term + "'}",
                    dataType: "json",
                    type: "POST",
                    contentType: "application/json; charset=utf-8",
                    success: function (data) {
                        response($.map(data.d, function (item) {
                            return {
                                SubCategoryName: item.SubCategoryName,
                                SubCategoryID: item.SubCategoryID,
                                json: item
                            }
                        }))
                    },
                    error: function (XMLHttpRequest, textStatus, errorThrown) {
                        alert(textStatus);
                    }
                });
            },
            focus: function (event, ui) {
                $('#city').val(ui.item.SubCategoryName);
                return false;
            },
            select: function (event, ui) {
                $('#city').val(ui.item.SubCategoryID);
                return false;
            },
        }).data("ui-autocomplete")._renderItem = function (ul, item) {
            return $("<li>")
            .append("<a>Company:" + item.SubCategoryName + "<br>Industry: " + item.SubCategoryID + "</a>")
            .appendTo(ul);
        };
    });

如果上面有什么问题,请告诉我。

提前非常感谢。

更新

我对我的引用进行了一些调整,如下所示:

<head>
    <meta charset="utf-8" />
    <title>@ViewBag.Title - My ASP.NET MVC Application</title>
    <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
    <meta name="viewport" content="width=device-width" />

    <script src="~/Scripts/jquery-2.1.0.min.js"></script>  

    @Scripts.Render("~/bundles/jqueryui")

    <link href="~/Content/ui-lightness/jquery-ui-1.10.4.custom.min.css" rel="stylesheet" />
    <link href="~/Content/menuStyles.css" rel="stylesheet" />
    <script src="~/Scripts/menu_jquery.js"></script>  
    <link href="~/Content/demos.css" rel="stylesheet" />

    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
</head>
<body> 


    @RenderSection("scripts", required: false)

我也改变了这个:

response($.map(data.d, function (item) {

对此:

response($.map(data, function (item) { // 没有.d

但是这不起作用,因为它只选择一个值,并且只有 ID 被选中,如此屏幕截图所示:

选择前:

选择后:

我不知道为什么会这样,如果你能帮忙的话..

更新:这是我修复后的实际 Json。现在唯一的问题是它不能多选

$(document).ready(function () {

    debugger;
    $('#city').autocomplete({
        source: function (request, response) {
            $.ajax({
                url: "Home/GetWhatever",
                data: "{ pre: request.term }",
                dataType: "json",
                type: "POST",
                contentType: "application/json; charset=utf-8",
                success: function (data) {
                    response($.map(data, function (item) {
                        return {
                            SubCategoryName: item.SubCategoryName,
                            SubCategoryID: item.SubCategoryID,
                            json: item
                        };
                    }));
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    alert(textStatus);
                }
            });
        },
        focus: function (event, ui) {
            $('#city').val(ui.item.SubCategoryName);
            return false;
        },
        select: function (event, ui) {
            $('#city').val(ui.item.SubCategoryName);
            return false;
        },
    }).data("ui-autocomplete")._renderItem = function (ul, item) {
        return $("<li>")
        .append("<a>" + item.SubCategoryName + " " + item.SubCategoryID + "</a>")
        .appendTo(ul);
    };
});

** 来自 Fiddler 的 @Daedalus 数据视图**

我刚刚注意到它是重复的,这可能是它不是多选的原因?

【问题讨论】:

  • @Tomanow 谢谢,但这还不够吗:$(function () {})。如您所见,它已经存在。我已经从 PartialView(它所在的位置)想到了主视图,但错误仍在发生。
  • 啊没看到。在旁注中,这对我来说看起来很奇怪:data: "{ 'pre':'" + request.term + "'}"。不应该是data: { pre: request.term }吗?您正在发送一个字符串...
  • 很抱歉,如果这太离谱了,但我在任何地方都看不到您的数据属性设置:data("ui-autocomplete")
  • @Tomanow 我实际上是 JQueryUI 的新手,我从这里的链接中获得了这段代码:dotnetawesome.blogspot.in/2013/12/…
  • @jamesemanon 不是这个集合。我看过 Fiddler,它似乎正在带回数据——但它没有显示在文本框中。而是显示上面的错误消息。

标签: jquery jquery-ui jquery-plugins jquery-ui-autocomplete


【解决方案1】:

完全免责声明,此答案中的大部分代码都是从jQuery UI API manual page for Autocomplete 复制(然后更改)的。

顺便说一句,您的自动完成功能不允许进行多项选择,原因很简单:它需要设置自定义处理程序才能发生这种情况,而您从未设置过该处理程序。

其次,代码正在做它应该做的事情。您从 item 对象中专门选择了 SubCategoryID 属性,它给出了您的评论,包含项目的 ID。

鉴于您在问题和 cmets 中所说的话,我猜这不是您的目标。因此,请记住,这是执行我认为您想要实现的目标的正确代码。我正在输入 cmets 来解释我所做的事情(再次注意,此内容的核心取自 API 页面,稍作改动):

$(function () {
    $('#city').autocomplete({
        source: function (request, response) {
            $.ajax({
                url: "Home/GetWhatever",
                data: "{ pre: request.term }",
                dataType: "json",
                type: "POST",
                contentType: "application/json; charset=utf-8",
                success: function (data) {
                    response($.map(data, function (item) {
                        return {
                            SubCategoryName: item.SubCategoryName,
                            SubCategoryID: item.SubCategoryID,
                            json: item
                        };
                    }));
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    alert(textStatus);
                }
            });
        },
        focus: function (event, ui) {
            /**
             * Here is the modifications I altered from the API manual page;
             * all I really added was extra focus event handling code and
             * an id field, if you just want the ids to be added to a
             * hidden input or such.
             */
            //Grab the current value of the input(s) and turn them into arrays
            var terms = this.value.split(/,\s*/),
                ids = $("#cityids").val().split(/,\s*/);
            //Remove the current input         ^ This is regex, it matches by            
            terms.pop();                      //  a comma followed by zero or
            ids.pop();                        //  more spaces.
            //Add the selected item to the end of the array(s)
            terms.push(ui.item.SubCategoryName);
            ids.push(ui.item.SubCategoryID);
            //Set the value of the inputs to the new strings.
            $("#city").val(terms.join(", "));
            $("#cityids").val(ids.join(", "));
            return false;
        },
        select: function (event, ui) {
            //Grab the current values of the input(s) and turn them into arrays
            var terms = this.value.split(/,\s*/),
                ids = $("#cityids").val().split(/,\s*/); 
            //Remove the current input                  
            terms.pop();
            ids.pop();
            //Add the selected item to the end of the array(s)
            terms.push(ui.item.SubCategoryName);
            ids.push(ui.item.SubCategoryID);
            //Add placeholder to get the comma-and-space at the end
            terms.push("");
            ids.push("");
            //Set the value of the inputs to the new strings.
            $("#city").val(terms.join(", "));
            $("#cityids").val(ids.join(", "));
            return false;
        },
    }).data("ui-autocomplete")._renderItem = function (ul, item) {
        return $("<li>")
            .append("<a>" + item.SubCategoryName + " " + item.SubCategoryID + "</a>")
            .appendTo(ul);
    };
});

DEMO

更新:

关于我对搜索词的疏忽,以下应该这样做,以及删除词位;

将您的“成功”处理程序代码/内容替换为以下内容:

var terms = request.term.split(/,\s*/),
    cur_term;
// Get the current term
if (terms[terms.length - 1] == "") {
    cur_term = terms[terms.length - 2];
} else if (terms.length > 1) {
    cur_term = terms[terms.length - 1]
} else {
    cur_term = request.term;
}
response($.map(data, function (item) {
    var reqterm = $.ui.autocomplete.escapeRegex(cur_term),
        //escape any regex
        reg = new RegExp("^"+reqterm,"gi"),
        //create the regex object with current term
        match = item.SubCategoryName.match(reg);
        //match the item name against the regex
    if (match !== null) {
        return { // match found, add object
            SubCategoryName: item.SubCategoryName,
            SubCategoryID: item.SubCategoryID,
            json: item
        }
    } else {
        return null; // No search term found, remove item from array.
    }
}));

上面搜索数据中的当前词,如果找到,只返回匹配项。

其次,将此代码插入您的.data() 代码之前,使其位于}).data() 之间;例如:}).data(/*etc*/) 变为 }).keydown(/*etc*/).data(/*etc*/)

.keydown(function(e) {
    var key = e.which;
    if (key == 8) { // backspace, add keycodes here to account for all keyboards
        var terms = $("#city").val().split(/,\s*/), //current terms
            ids = $("#cityids").val().split(/,\s*/), //current ids
            placeholder = terms[terms.length - 1]; //current placeholder
        // remove the current input, as well as the placeholder if applicable
        terms.pop();
        ids.pop();
        if (placeholder == "") {
            terms.pop();
            ids.pop();
        }
        // add the placeholders back
        terms.push(" ");
        ids.push(" ");
        $("#city").val(terms.join(", "));
        $("#cityids").val(ids.join(", "));
    }
})

DEMO_2

【讨论】:

  • 非常感谢。今晚回家后,我将看看这对我的项目有何影响。但这一切现在都说得通了,我相信一切都会好起来的。再次感谢 - 太好了,内容丰富。
  • 谢谢,这当然有效,唯一的问题是它显示所有数据项;它不会根据用户的字符输入过滤它们。另外我想知道我怎么可能以某种方式“设置”它,如果用户删除选择,它会被一次性删除,而不是按退格键时一个字符一个字符地删除?
  • 我不确定这是否适合新线程。@Daedalus
  • @t_plusplus 我会看看我能做什么。
猜你喜欢
  • 1970-01-01
  • 2019-11-22
  • 2013-11-24
  • 2021-05-03
相关资源
最近更新 更多