未捕获的类型错误 - 无法在JQuery自动完成中读取未定义的属性“长度”

时间:2014-02-16 23:31:44

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

我正在尝试实现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)

我也改变了这个:

响应($ .map(data.d,function(item){

到此:

响应($。map(data,function(item){//不带.d

然而,这不起作用,因为它只选择一个值,而且只是在此屏幕截图中选择的ID:

选择之前:

enter image description here

选择后:

enter image description here

我不知道为什么会发生这种情况,如果你能帮忙的话......

更新:这是我修复后的实际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数据视图**

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

1 个答案:

答案 0 :(得分:2)

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

除此之外,您的自动完成功能不允许进行多项选择,原因很简单:它需要设置自定义处理程序才能实现此类操作,并且您永远不会设置该处理程序。

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

鉴于你在问题和评论中所说的话,我猜想这不是你的目标。所以,记住,这是正确的代码来做我认为你想要实现的。我正在发表评论来解释我的所作所为(并再次注意,其核心内容来自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