【问题标题】:Kendo UI - JSON Response for - Grid using Remote Data Source W/Server Grouping & Server AggregatesKendo UI - JSON 响应 - 使用带有服务器分组和服务器聚合的远程数据源的网格
【发布时间】:2016-05-02 13:57:56
【问题描述】:

我有一个项目,我在其中使用 KendoUI Grid,使用服务器而不是本地获取数据。

我不确定我的服务器应该提供什么 JSON 响应才能使分组工作。我的目标是当用户将一列拖到分组标题时,我知道要返回什么样的 JSON 响应,以便 GRID 按该列和可能添加到该标题的任何其他列进行分组。

鉴于上图,我如何创建一个 JSON 响应来实现它(因此它显示了它应该分组的内容)? 我知道我必须自己在服务器上执行此操作,但不确定 JSON 需要如何格式化。此外,如果我想在创建组时在组旁边显示一个“计数”字段,以便我知道每个组中有多少项目(我认为这是汇总?)

我当前的网格代码如下所示:

<div id="grid" style="height:100%;"></div>
<script>
    $(window).on("resize", function() {
      kendo.resize($("#grid"));
    });

    var crudServiceBaseUrl = "/api",
    dataSource = new kendo.data.DataSource({
        transport: {
            read:  {
                url: crudServiceBaseUrl + "/companies",
                dataType: "json",
                type: "POST"
            },
            update: {
                url: crudServiceBaseUrl + "/companies/update",
                dataType: "json",
                type: "POST"
            },
            destroy: {
                url: crudServiceBaseUrl + "/companies/destroy",
                dataType: "json",
                type: "POST"
            },
            create: {
                url: crudServiceBaseUrl + "/companies/create",
                dataType: "json",
                type: "POST"
            },
            parameterMap: function(options, operation) {
                if (operation !== "read" && options.models) {
                    return {models: kendo.stringify(options.models)};
                }
            }
        },
        error: function (e) {
            /* the e event argument will represent the following object:
            {
                errorThrown: "custom error",
                errors: ["foo", "bar"]
                sender: {... the Kendo UI DataSource instance ...}
                status: "customerror"
                xhr: null
            }
            */
            //alert("Status: " + e.status + "; Error message: " + e.errorThrown);
            console.log("Status: " + e.status + "; Error message: " + e.errorThrown);
            console.log("Errors: " + e.errors.join("; "));
        },
        autoSync: false,
        serverPaging: true,
        serverFiltering: true,
        serverSorting: true,
        serverGrouping: true,
        serverAggregates: true,
        pageSize: 20,
        columnResizeHandleWidth: 6,
        schema: {
            total: "itemCount",
            data: "items",
            groups: "groups",
            aggregates: "aggregates",
            group: {
                field: "phone", aggregates: [{ field: "phone", aggregate: "count" }]
            },
            model: {
                id: "id",
                fields: {
                    id: { editable: false, nullable: true },
                    name: { validation: { required: true } },
                    phone: { 
                        type: "string",
                        validation: { 
                            required: true,
                            phonerule: function(e){
                                if (e.is("[data-phonerule-msg]"))
                                {
                                    var input  = e.data('kendoMaskedTextBox');
                                    //If we reached the end of input then it will return -1 which means true, validation passed
                                    //Otherwise it won't === -1 and return false meaning all the characters were not entered.
                                    return input.value().indexOf(input.options.promptChar) === -1;
                                }
                                return true; //return true for anything else that is not data-phonerule-msg
                            } 
                        } 
                    },
                    email: { type: "string", validation: { required: true, email:true } }
                }
            }
        }
    });

    $("#grid").kendoGrid({
        dataSource: dataSource,
        groupable: true,
        sortable: {
            mode: "multiple",
            allowUnsort: true
        },
        selectable: "multiple cell",
        allowCopy:true,
        toolbar: ["create","excel"],
        excel: {
            fileName: "Kendo UI Grid Export.xlsx",
            //Below is only used as fallback for old browsers without support
            proxyURL: "//demos.telerik.com/kendo-ui/service/export",
            filterable: true
        },
        pageable: {
            refresh: true,
            pageSizes: true,
            buttonCount: 5
        },
        reorderable: true,
        resizable: true,
        columnMenu: true,
        filterable: true,
        editable: "popup",
        mobile: true,
        columns: [
            { 
                field: "name",
                title: "Company Name",
                aggregates: ["count"],
                groupFooterTemplate: "Count: #=count#"
            },
            { 
                field: "phone",
                title: "Phone",
                editor: function(container, options){
                    //pattern="[(][0-9]{3}[)] [0-9]{3}-[0-9]{4}"
                    var input = $('<input type="tel" data-phonerule-msg="Invalid Phone Number!" class="k-textbox"  required />');
                    input.attr("name", options.field);
                    input.kendoMaskedTextBox({
                        mask: "(999) 000-0000"
                    });
                    input.appendTo(container);
                },
                aggregates: ["count"],
                groupFooterTemplate: "Count: #=count#"
            },
            { 
                field: "email",
                title: "Email",
                editor: function(container, options){
                    var input = $('<input type="email" data-email-msg="Invalid email!" class="k-textbox" required/>');
                    input.attr("name", options.field);
                    input.appendTo(container);
                },
                aggregates: ["count"],
                groupFooterTemplate: "Count: #=count#"
            },
            { 
                command: ["edit", "destroy"],
                title: "Operations",
                width: "240px"
            }
        ],
    });
</script>

我当前通过 Symfony 3.0 生成演示 javascript 的代码如下。

DefaultController.php

/**
     * @Route("/api/companies", name="api_companies_read")
     */
public function apiCompaniesReadAction(Request $request)
    {
        $data["itemCount"] = "7";

        // $tdata["field"] = "";
//      $tdata["value"] = "";
//      $tdata["items"] = "hey";
//      $data["groups"][] = $tdata;

        $tdata["id"]    = "1";
        $tdata["name"] = "Joe";
        $tdata["phone"] = "(714)475-8651";
        $tdata["email"] = "Joe@whatever.com";

        $data["items"][] = $tdata;

        $tdata["id"]    = "2";
        $tdata["name"] = "Rachel";
        $tdata["phone"] = "(563)812-4184";
        $tdata["email"] = "rachel@yahoo.com";

        $data["items"][] = $tdata;

        $tdata["id"]    = "3";
        $tdata["name"] = "John";
        $tdata["phone"] = "(563)812-4184";
        $tdata["email"] = "John@yahoo.com";

        $data["items"][] = $tdata;

        $tdata["id"]    = "4";
        $tdata["name"] = "Richard";
        $tdata["phone"] = "(563)812-4184";
        $tdata["email"] = "John@yahoo.com";

        $data["items"][] = $tdata;

        $tdata["id"]    = "5";
        $tdata["name"] = "Sister";
        $tdata["phone"] = "(563)812-4184";
        $tdata["email"] = "John@yahoo.com";

        $data["items"][] = $tdata;

        $tdata["id"]    = "6";
        $tdata["name"] = "Brother";
        $tdata["phone"] = "(563)812-4184";
        $tdata["email"] = "Brother@yahoo.com";

        $data["items"][] = $tdata;

        $tdata["id"]    = "7";
        $tdata["name"] = "Sibling";
        $tdata["phone"] = "(563)812-4184";
        $tdata["email"] = "Sibling@yahoo.com";

        $data["items"][] = $tdata;

//      schema: {
//          total: "total",
//          model: {
//              id: "CompanyID",
//              fields: {
//                  CompanyID: { editable: false, nullable: true },
//                  Name: { validation: { required: true } },
//                  Phone: { type: "string" },
//                  Email: { type: "string" }
//              }
//          }
//      }

        // replace this example code with whatever you need
        return new JsonResponse($data);

    }

它创建的当前 JSON 如下所示。

JSON

{"itemCount":"7","items":[{"id":"1","name":"Joe","phone":"(714)475-8651","email":"Joe@whatever.com"},{"id":"2","name":"Rachel","phone":"(563)812-4184","email":"rachel@yahoo.com"},{"id":"3","name":"John","phone":"(563)812-4184","email":"John@yahoo.com"},{"id":"4","name":"Richard","phone":"(563)812-4184","email":"Richard@yahoo.com"},{"id":"5","name":"Sister","phone":"(563)812-4184","email":"Sister@yahoo.com"},{"id":"6","name":"Brother","phone":"(563)812-4184","email":"Brother@yahoo.com"},{"id":"7","name":"Sibling","phone":"(563)812-4184","email":"Sibling@yahoo.com"}]}

我发现一篇文章 here 看起来很接近我想要的,只是很难理解。 This 也可能有帮助。

我创建了JSFiddle 可以玩,只需要提供有效数据。

更新

我让服务器分页工作!第一个主要变化是数据源的传输,您必须更改 parameterMap 以发送 json,以便您可以访问它试图告诉您的服务器进行更改的内容。

dataSource = new kendo.data.DataSource({
        transport: {
            read:  {
                url: crudServiceBaseUrl + "/companies",
                dataType: "json",
                type: "POST"
            },
            update: {
                url: crudServiceBaseUrl + "/companies/update",
                dataType: "json",
                type: "POST"
            },
            destroy: {
                url: crudServiceBaseUrl + "/companies/destroy",
                dataType: "json",
                type: "POST"
            },
            create: {
                url: crudServiceBaseUrl + "/companies/create",
                dataType: "json",
                type: "POST"
            },
            parameterMap: function(options, operation) {
                return kendo.stringify(options);
            }
        },

我的数据源如上所示,但您可以根据自己的需要进行调整。接下来是我的php文件。

PHP /公司

/**
     * @Route("/api/companies", name="api_companies_read")
     */
    public function apiCompaniesReadAction(Request $request)
    {

        $request_body = file_get_contents('php://input');
        $json = json_decode($request_body);

        //Based on the JSON Payload response adjust the search in the database
        if($json){
            $page       = $json->page;
            $pageSize   = $json->pageSize;
            $skip       = $json->skip;
            $take       = $json->take;
        }else{
            $page = 1;
            $pageSize = 20;
            $skip = 1;
            $take = 1;
        }

        $repository = $this->getDoctrine()->getRepository('AppBundle:Company');

        /*
        findBy(
            array        $criteria,
            array        $orderBy  = null, 
            integer|null $limit    = null,
            integer|null $offset   = null
        )
        */

        $company_total = $repository->findAll();
        $company_records = $repository->findBy(array(),array(),$pageSize,($page-1)*$pageSize);

        $data["total"] = count($company_total);

        foreach($company_records as $company){
            $temp["id"]     = $company->getId();
            $temp["name"]   = $company->getName();
            $temp["phone"]  = $company->getPhone();
            $temp["email"]  = $company->getEmail();
            $data["data"][] = $temp;
        }

        //converts data to JSON
        return new JsonResponse($data);

    }

请记住,上面是一个 Symfony 3.0 php 实现,使用注解来设置路由。该代码中的重要部分是。

$request_body = file_get_contents('php://input');
        $json = json_decode($request_body);

        //Based on the JSON Payload response adjust the search in the database
        if($json){
            $page       = $json->page;
            $pageSize   = $json->pageSize;
            $skip       = $json->skip;
            $take       = $json->take;
        }else{
            $page = 1;
            $pageSize = 20;
            $skip = 1;
            $take = 1;
        }

file_get_contents('php://input'); 获取 KendoUI 控件发回的 javascript 对象。

更新 #3 让服务器排序正常工作!

以下是使用 Symfony 3.0 和 Doctrine 进行服务器排序的示例实现!

PHP

/**
     * @Route("/api/companies", name="api_companies_read")
     */
    public function apiCompaniesReadAction(Request $request)
    {
        $request_body = file_get_contents('php://input');
        $json = json_decode($request_body);

        //print_r($json);

        //default parameters in case of error.
        $page = 1;
        $pageSize = 20;
        $skip = 1;
        $take = 1;
        $sort = array();

        //Based on the JSON Payload response adjust the search in the database
        if(isset($json)){
            $page       = $json->page;
            $pageSize   = $json->pageSize;
            $skip       = $json->skip;
            $take       = $json->take;

            if(isset($json->sort)){
                //"sort":[{"field":"name","dir":"asc"}]}:

                foreach($json->sort as $sortObj){
                    $sort[$sortObj->field] = $sortObj->dir;
                }
            }

        }

        $repository = $this->getDoctrine()->getRepository('AppBundle:Company');

        /*
        findBy(
            array        $criteria,
            array        $orderBy  = null, 
            integer|null $limit    = null,
            integer|null $offset   = null
        )
        */

        $company_total = $repository->findAll();
        $company_records = $repository->findBy(array(),$sort,$pageSize,($page-1)*$pageSize);

        $data["total"] = count($company_total);

        foreach($company_records as $company){
            $temp["id"]     = $company->getId();
            $temp["name"]   = $company->getName();
            $temp["phone"]  = $company->getPhone();
            $temp["email"]  = $company->getEmail();
            $data["data"][] = $temp;
        }

        //converts data to JSON
        return new JsonResponse($data);

    }

【问题讨论】:

  • 有人有什么想法吗?

标签: json kendo-ui telerik kendo-grid telerik-grid


【解决方案1】:

第一个链接是正确的。我必须将数据从网格导出为 pdf 和 excel,以遵守网格分组。我终于弄清楚了语义。网格具有列和数据对象,您可以通过网格调用获得它们。数据对象保存分组信息。这里是处理操作。

简而言之,您必须递归地迭代数据对象才能确定分组。对于数据中的每个元素,您需要检查 data[x].value 是否存在。如果它存在,那么它是一个带有子数据的组对象。如果它不存在,那么您使用普通的 data[row][column].field 来获取子数据。这里的技巧是为每个 dat[0].value 有数据的点调用一个递归函数,最后在展开时处理 data[row][column]。

下面是一个 js 函数,您可以使用它来检查 Grid 的 json dta。我会在您的网格中添加一两个组,并查看应用/不应用分组的数据之间的差异,这应该是您需要添加到数据中的内容....我认为您几乎将数据添加为 data={[ [],[]]}除非是组,否则就是data={[value='groupName',{[],[]}]}。

function showData(gridName) {
        var grid = $('#' + gridName).data('kendoGrid');
        var data = grid.dataSource.data().toJSON();
        console.log(data);
    }

【讨论】:

  • 这很复杂,我的特定项目使用 php,但我可以尝试翻译,不幸的是,我不是 c# 专家,所以很难弄清楚那里发生了什么。我想我仍然对 JSON 响应的样子感到困惑,您能否提供代码生成的示例?
  • 感谢您尝试解决这个问题,这非常复杂。
  • 对不起,我以为你在读数据。我添加了一个 js 函数来检查分组时数据的样子。这是无证的,可能会改变,我会谨慎行事。
  • 只是好奇,应用分组时 php 包装器不应该返回所需的格式吗?
  • Yes & No,我调查了它,但对如何使用 PHP Wrappers 来做到这一点感到非常困惑。我有点困惑的原因是因为我认为包装器依赖于他们自己的模型定义,但我的模型是在学说中定义的。不过,我会使用您制作的那个功能,这肯定会帮助我更好地理解格式。如果可能的话,我会再次研究 PHP 包装器,看看我是否能找到一种方法让它与 Doctrine Entities 一起工作。
猜你喜欢
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 2013-01-22
  • 1970-01-01
  • 2022-08-19
  • 1970-01-01
  • 2013-11-23
  • 2018-09-02
相关资源
最近更新 更多