Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error rendering data with Javascript / KendoUI autocomplete - Object #<Object> has no method 'slice' - how to resolve?

I am following the Using Kendo UI with MVC4 WebAPI OData and EF article. After installing KendoUI and making sure all references are set, I type in three characters, and get the following error:

Uncaught TypeError: Object # has no method 'slice'

Root of the Problem

To save reading through the updates: Through debugging I found that the issue is that JS is expecting to parse an array, where it isn't available in the data - at the root. In the data hierarchy, it's one level in.

Original Problem

I cleaned up kendo.web.min.js and the error is occuring around line 3498:

success: function (n) {
     var i = this,
         r = i.options;
     return i.trigger(wt, {
         response: n,
         type: "read"
     }), n = i.reader.parse(n), i._handleCustomErrors(n) ? (i._dequeueRequest(), t) : (i._pristine = et(n) ? e.extend(!0, {}, n) : n.slice ? n.slice(0) : n, i._total = i.reader.total(n), i._aggregate && r.serverAggregates && (i._aggregateResult = i.reader.aggregates(n)), n = i._readData(n), i._pristineData = n.slice(0), i._data = i._observe(n), i._addRange(i._data), i._process(i._data), i._dequeueRequest(), t)

The Kendo UI widgets are loading just fine as well as the css:

<link href="~/Content/kendo/kendo.common.min.css" rel="stylesheet" />
<link href="~/Content/kendo/kendo.default.min.css" rel="stylesheet" />
<script src="~/Scripts/jquery-1.9.1.min.js"></script>
<script src="~/Scripts/kendo/kendo.web.min.js"></script>
<script src="~/Scripts/kendo/kendo.aspnetmvc.min.js"></script>
<script src="~/Scripts/appScripts.js"></script>

And I am seeing the same error both with using the Razor MVC helper/extension:

@(Html.Kendo().AutoComplete()
    .Name("userAutoComplete")                   // specifies the "id" attribute of the widget
    .DataTextField("USERNAME")
    .DataSource(source =>
        {
            source.Read(read =>
                {
                    read.Url("/api/user");
                })
                  .ServerFiltering(true);       // if true, the DataSource will not filter the data on the client
        }
    )
)

and through directly through JS:

/// <reference path="kendo/kendo.aspnetmvc.min.js" />
/// <reference path="kendo/kendo.core.min.js" />
/// <reference path="kendo/kendo.autocomplete.min.js" />
/// <reference path="kendo/kendo.web.min.js" />

$(document).ready(function () {
    // load up KendoUI

    // gets data from /api/user
    var dataSource = new kendo.data.DataSource({
        transport: {
            read: {
                url: "/api/user"
            }
        }
    });

    $("#userSearch").kendoAutoComplete({
        dataSource: dataSource,
        dataTextField: "USERNAME",
        minLength: 3
    });

    $("#userSearch").on('input', function () {
        console.log($("#userSearch").val());
    });

}); // $(document).ready()

I'm sure this is something simple that I may be missing. I have tried both with the web and all js files.

Any assistance would be appreciated.

-- UPDATE --

The only real html missing from that content is the <input id="userAutoComplete" />

I created a brand new solution and a very simple view, based on one of the Kendo UI examples that gets JSON data from http://api.geonames.org, and getting the same error.

I thought that using the newest JS library (//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js may have been causing a problem so I tried the 1.7 lib. Same issue:

@using Kendo.Mvc.UI

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>

    <link rel="stylesheet" href="@Url.Content("~/Content/kendo.common.min.css")">
    <link rel="stylesheet" href="@Url.Content("~/Content/kendo.default.min.css")">
    <link rel="stylesheet" href="@Url.Content("~/Content/kendo.dataviz.min.css")">

    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script> 

    <script src="@Url.Content("~/Scripts/kendo.web.min.js")"></script>
    <script src="@Url.Content("~/Scripts/kendo.aspnetmvc.min.js")"></script>
    <script src="@Url.Content("~/Scripts/kendo.dataviz.min.js")"></script>

    <script type="text/javascript">

        $(document).ready(function () {
            $("#autoComplete").kendoAutoComplete({
                minLength: 6,
                dataTextField: "title",
                filter: "contains",
                dataSource: new kendo.data.DataSource({
                    transport: {
                        read: {
                            url: "http://api.geonames.org/wikipediaSearchJSON",
                            data: {
                                q: function () {
                                    return $("#autoComplete").data("kendoAutoComplete").value();
                                },
                                maxRows: 10,
                                username: "demo"
                            }
                        }
                    },
                    schema: {
                        data: "geonames"
                    }
                }),
                change: function () {
                    this.dataSource.read();
                }
            })
        });

    </script>    


</head>
<body>
    <div>

        <input id="autoComplete"/>

    </div>
</body>
</html>

-- UPDATE --

Using the code above, I went back and tried it again - it worked fine. After trying several more times, I experienced the same issue. This was due to the valid JSON data changing to the following:

{"status":{"message":"the daily limit of 30000 credits for demo has been exceeded. Please use an application specific account. Do not use the demo account for your application.","value":18}}

... which lead me to look at the formatting of the data coming from my API (looking at it in Fiddler:

Instead of:

JSON ---{... data...

it's

JSON
---$id=1
---$values
------{}
---------$id=2
---------CREATEDATETIME...
[email protected]
---------GROUPS
------------$id=...
------------$id=...
---------USERNAME=someusername
------{}
---------$id=4
.
.
.

So the error is caused by the array not being accessible where the it's expected - instead of the root, it's one level deep.

How do I get data binding to the one-level-deep rather than the root of the JSON object?

Thanks.

like image 346
ElHaix Avatar asked Jul 24 '13 14:07

ElHaix


3 Answers

I had the same error with a ComboBox that I was using as an autocomplete. In my controller, the return statement was

return Json(model.ToDataSourceResult(dataSourceRequest), JsonRequestBehavior.AllowGet)

which I changed to

return Json(model, JsonRequestBehavior.AllowGet)

This provided the array at the root level instead of one level deep for me.

like image 98
Xanothos Avatar answered Nov 13 '22 23:11

Xanothos


The solution for this was to traverse the data hierarchy by describing the result format.

Since the array is contained in $values, I used the following data source/schema definition:

    // gets data from /api/user
    var dataSource = new kendo.data.DataSource({
        transport: {
            read: {
                url: "/api/user"
            }
        },
        schema: {                               // describe the result format
            data: function(data) {              // the data which the data source will be bound to is in the values field
                console.log(data.$values);
                return data.$values;
            }
        }
    });

One thing that would be nice is to be able to add a data schema type in the Razor helper - which doesn't seem to be supported at this time.

Thus, the following still would not work:

@(Html.Kendo().AutoComplete()
        .Name("userAutoComplete")                   // specifies the "id" attribute of the widget
        .Filter("startswith")
        .Placeholder("Type user name...")
        .DataTextField("USERNAME")
        .DataSource(source =>
            {
                source:
                    source.Read(read =>
                        {
                            read.Url("/api/user");
                        })
                        .ServerFiltering(true);       // if true, the DataSource will not filter the data on the client

            }
        )
)
like image 35
ElHaix Avatar answered Nov 14 '22 00:11

ElHaix


This worked for me:

var dataSource = new kendo.data.DataSource({
        transport: {
            read:
            {
                url: "api/dashboard"
            }
        },
        schema: {
            **data: function (data)
            {
                return [data];
            }**
        }
    });

My response wasn't an array, i was returning from the server a response object like this:

{"Field1":0,"Field2":0,"Field3":0}
like image 2
brittongr Avatar answered Nov 13 '22 23:11

brittongr