• Kendo UI Grid 批量编辑使用总结


    项目中使用Kendo UI Grid控件实现批量编辑,现在将用到的功能总结一下。

    批量编辑基本设置

    Kendo Grid的设置方法如下:

                        $("#grid").kendoGrid({
                            toolbar: ["create","save", "cancel"],
                             columns: [
                                { field: "OBJECTID", title: "ID" },
                                ...
                            ],
                            dataSource: {
                                transport: {
                                    read: {
                                        url: myRoot + "GetPagedData"
                                    },
                                    update: {
                                        url: myRoot + "UpdateBatch"
                                    },
                                    create: {
                                        url: myRoot + "UpdateBatch"
                                    },
                                    delete:{
                                        url:myRoot+"DeleteDate"
                                    }
                                },
                                pageSize: 100,
                                serverPaging: true,
                                serverSorting: true,
                                schema: {
                                    total: "rowCount", 
                                    data: "Rows",
                                    model: {
                                        id: "OBJECTID",
                                        fields: {
                                            OBJECTID: { editable: false, nullable: true },
                                            NAME: { editable: true, validation: { required: true } },
                                            ...
                                        }
                                    }
                                },
                                batch: true,  
                            },
                            pageable: {
                                pageSize: 10
                            },
                            height: "600px",
                            editable: true
                        });
    
    
    • toolbar:创建网格中的按钮,这里创建“新增”、“保存”和“取消”。
    • columns:在网格中显示的列,这是一个数组,每一列可以定义字段的名称,显示的文本,显示的模板和自定义的编辑器
    • dataSource:定义了与网格相关的kendo dataSource对象。在transport中定义了进行CRUD的对象(或者函数),如果批量修改,需要在dataSource中将batch设置为true。如果批量修改,还需要在schema中设置model,包括id和各个字段的定义。
    • editable属性需要设置为true。

    基本设置完成后,网格就可以进行批量编辑了,点击网格中的单元格,会加载动态文本框,进行编辑,编辑完成后,改变值的网格会有变化提示。

    Grid批量编辑中的下拉框设置

    在前面的例子中,网格中显示人员所在的部门,我们在编辑时,需要使用下拉框选择所在的部门:

    这里需要解决几个问题:
    1、我们在数据库中保存的是部门的id,不是部门的名称,而在显示时,需要显示部门的名称。
    2、在编辑时,我们需要加载下拉框,并获取部门的数据,进行编辑。

    为了解决第一个问题,我们在返回的数据中,不仅返回部门的id,还返回部门的名称,

                            model: {
                                        id: "OBJECTID",
                                        fields: {
                                            ...
                                            DEPARTMENTID: { editable: true, },
                                            DEPARTMENTID_DicText: { editable: false, nullable: true  },
                                            ...
                                        }
                                    }
    

    在模型定义中,定义DEPARTMENTID为可编辑的,DEPARTMENTID_DicText不可编辑。
    在columns的定义中,定义DEPARTMENTID的显示模板为DEPARTMENTID_DicText:

     { field: "DEPARTMENTID", title: "部门", editor: categoryDropDownEditor, template: "#=DEPARTMENTID_DicText#" },
    

    这样DEPARTMENTID在网格显示时,实际显示的是DEPARTMENTID_DicText

    为了实现下拉框选择,我们创建自定义的编辑器,categoryDropDownEditor,这个编辑器是一个函数:

                    //自定义编辑控件,下拉框
                    function categoryDropDownEditor(container, options) {
                        $('<input  name="' + options.field + '"/>')
                            .appendTo(container)
                            .kendoDropDownList({
                                autoBind: false,
                                dataTextField: "Text",
                                dataValueField: "Value",
                                height: 600,
                                dataSource: {
                                    transport: {
                                        read: {
                                            url: myRoot + "GetDictionary"
                                        }
                                    }
                                },
                                change: function (e) {
                                    options.model[options.field + "_DicText"] = e.sender.text();
                                }
                            });
                    }
    

    这个函数中创建了一个input控件,并转换为kendoDropDownList下拉框,下拉框通过ajax获取部门的数据,选择后,修改模型中保存的数据。

    Grid批量编辑中的日期编辑器设置

    前面我们讨论了在Kendo UI Grid中下拉框的设置,这里讨论如何设置日期编辑器。

    自定义日期编辑器

    在上面的例子中,有入职日期字段,需要使用日期选择器进行编辑,由于kendo的日期型在服务器端不容易转换,所有我们采用字符串进行传输,因此在模型中,我们没有将这个字段定义为日期型,而是保持为字符型:

                                    model: {
                                        id: "OBJECTID",
                                        fields: {
                                            ...
                                            JOINDATE: { editable: true, format: "yyyy-MM-dd", type: "string" },
                                            ...
                                        }
                                    }
    

    在columns中:

                            columns: [
                                ...
                                { field: "JOINDATE", title: "入职日期", editor: dateEditor },
                                ...
                            ],
    

    在这里,我们定义了这个列的自定义编辑器,是一个函数,自定义的日期编辑器函数如下:

                    //自定义编辑控件,日期
                    function dateEditor(container, options) {
                        $('<input  name="' + options.field + '"/>')
                            .appendTo(container)
                            .kendoDatePicker(
                                {
                                format: "yyyy-MM-dd",
                                culture: "zh-CN",
                                    change: function (e) {
                                        options.model[options.field] = kendo.toString(e.sender.value(), "yyyy-MM-dd");
                                    }
                                })
                    }
    

    在这个函数里,创建一个input标签,并转换为kendo DatePicker,在change事件中改变模型中的值。这样就完成了网格单元格编辑的日期编辑器。

    Grid批量编辑中的Checkbox编辑器设置

    我们需要在网格中用checkbox显示ISFULLTIME,如果值为1,显示选中,如果为0,显示没有选中。可以通过创建模板的方式实现。模板代码如下:

     { template: '#=dirtyField(data,"ISFULLTIME")#<input type="checkbox" #=ISFULLTIME== 1 ? \'checked="checked"\' : "" # class="chkbx" ref="ISFULLTIME" />', width: 110 },
    

    我们在change事件中响应选择动作,改变模型中相应的值。

     $("#grid .k-grid-content").on("change", "input.chkbx", function (e) {
                            var field = $(this).attr("ref")
                            var grid = $("#grid").data("kendoGrid"),
                            dataItem = grid.dataItem($(e.target).closest("tr"));
    
                            dataItem.set(field, this.checked ? 1 : 0);
                        });
    

    我们还需要处理脏数据,也就是正在编辑的数据,如果数据发生了改变,则在网格中进行标识。这个函数的代码如下:

    function dirtyField(data, fieldName) {
                            var hasClass = $("[data-uid=" + data.uid + "]").find(".k-dirty-cell").length < 1;
                            if (data.dirty && data[fieldName]!=data[fieldName+"_DICTEXT"] && hasClass) {
                                return "<span class='k-dirty'></span>"
                            }
                            else {
                                return "";
                            }
                        }
    

    Grid批量编辑中的Checkbox编辑器另一种方法

    在这个例子中,有一个是否全职的字段,ISFULLTIME,这个字段是数值型,用1和0表示true和false,在编辑时,我们希望使用checkbox进行编辑,但希望获得的值是1和0,而不是true和false。
    在model中的定义这个字段和一个附加字段,用于编辑:

                                   model: {
                                        id: "OBJECTID",
                                        fields: {
                                            ...
                                            ISFULLTIME: { editable: true },
                                            ISFULLTIME_DICTEXT: { editable: true}
                                        }
    

    在columns中的定义,注意这里我们编辑的是ISFULLTIME_DICTEXT:

                            columns: [
                                ...
                                { field: "ISFULLTIME_DICTEXT", title: "是否全职", editor: customBoolEditor, template: "#=GetFullTime(ISFULLTIME)#" },
                            ],
    

    这里我们希望显示“是”和“否”,因此模板调用了转换函数:

                   function GetFullTime(va) {
                        if (va == 1) return "是";
                        return "否";
                    }
    

    自定义的编辑器如下:

    
                    //自定义编辑控件,checkbox
                    function customBoolEditor(container, options) {
                        var guid = kendo.guid();
                        $('<input class="k-checkbox" id="' + guid + '" type="checkbox" name="' + options.field + '" data-type="boolean" data-bind="checked:' + options.field + '">').appendTo(container)
                            .on("click", function (e) {
                                var field = options.field.replace("_DICTEXT", "");
                                if (e.target.checked)
                                    options.model[field] = 1;
                                else
                                    options.model[field] = 0;
                            });
                        $('<label class="k-checkbox-label" for="' + guid + '">&#8203;</label>').appendTo(container);
                    }
    

    这里,在控件值改变时,将模型相关的值改变为1或0。

    在网格之外添加“新增”、“保存”和“取消”

    在网格中增加“新增”、“保存”和“取消”很容易,只要在网格定义中增加toolbar: ["create","save", "cancel"]就可以了。但在某些情况下,我们希望在网格之外增加这些功能按钮,并通过调用Api实现相应的功能。

    如果我们希望在网格之外添加这几个按钮,可以直接调用dataSource的相关api:
    html代码:

            <span id="btnAdd" class="btn btn-default">新增</span>
            <span id="btnSave" class="btn btn-default">保存</span>
            <span id="btnCancel" class="btn btn-default">取消修改</span>
    

    相关的JS代码如下:

                        //增加保存按钮
                        $("#btnSave").bind("click", function () {
                            var grid = $("#grid").data("kendoGrid");
                            grid.dataSource.sync();;
                        });
    
                        //增加取消按钮
                        $("#btnCancel").bind("click", function () {
                            var grid = $("#grid").data("kendoGrid");
                            grid.dataSource.cancelChanges();
                        });
    
                        //增加添加按钮
                        $("#btnAdd").bind("click", function () {
                            var grid = $("#grid").data("kendoGrid");
                            grid.dataSource.add();
                        });
    

    这些按钮执行效果与网格中toolbar定义的按钮效果相同。

    为Kendo Grid 增加自定义统计行

    Kendo Grid支持增加列统计的功能,对某一列的数据在底部显示合计值、平均值等等。但这些功能都是在客户端进行的,如果数据量很大,需要在服务端进行分页处理等,就不能使用这些客户端的功能,而是需要在服务端进行计算,然后在网格中显示。为了实现这种需求,我们需要:

    • 在服务端增加计算统计值的Api
    • 在客户端调用这个Api,使用自定义模板显示

    这里假设我们已经有了在服务计算统计值的Api,主要说明如何在客户端显示这些计算值。

    首先,需要增加保存统计值的对象:

    var agData = {};//保存从服务器Api获取的统计数据
    

    然后,在grid的列定义中增加footerTemplate,比如:

     { field: "AGE", title: "年龄", width: "500px", footerTemplate:"<span id='footerAGE'>#=getAgData('AGE')#</span>"},
    
    

    在模板里,我们使用一个函数获取统计值,获取函数如下:

    function getAgData(field) {
        if (agData[field]) return agData[field];
        return "";
    }
    

    在查询函数中调用服务端的Api,获取统计数据,并将统计数据保存到agData:

             function doSearch() {
                //网格查询部分略
    
                //这里通过自定义的Api查询统计数据,postdata中包含查询条件
                 MyApi.getSumData(postdata, function (res) {
                     agData = res;
                     });
    
             }
    

    Grid保持行展开状态

    在使用Kendo UI Grid时,如果重新绑定,也就是当dataBound事件被触发时,原来展开的行会收起,如果希望保持行的展开状态,需要在行展开时,记录展开行的id,然后在重新绑定时,回复展开的状态。我们可以将展开行的id保持在本地存储中。下面的例子是使用MVVM下的代码:

     <div id="dsgrid" class="grid"
                             data-role="grid"
                             data-sortable="true"
                             data-toolbar="['create']"
                             data-detail-init="viewModel.dsgrid_detailInit"
                             data-bind="source: dsSource, events: { dataBound: ds_dataBound,detailExpand:ds_DetailExpand, detailCollapse:ds_DetailCollapse }"
                             data-editable='{"mode": "popup" }'
                             data-columns='[
                                     {"field":"Name","title":"名称"},
                                     {"field":"Title","title":"说明"},
                                     {"field":"TableName","title":"数据库数据源表名称"},
                                      {"field":"GetDataUrl","title":"Api数据源Url"},
                                     {"field":"TextField","title":"文本字段"},
                                     {"field":"ValueField","title":"值字段"},
                                     {"command": [ "edit", "destroy" ], "filterable": false, "sortable": false, "width:": "240px"}
                                     ]'
                             data-detail-template='dssubgrid'
                             data-scrollable="false">
                        </div>
    
    

    代码中声明了三个事件,dataBound,detailExpand和detailCollapse,在detailExpand事件中,记录下展开行对应的数据id:

    ds_DetailExpand: function (e) {
                        var grid = $("#dsgrid").data("kendoGrid");
                        var item = grid.dataItem(e.masterRow);
                        var items = localStorage['expanded'];
                        if (items) {
                            items = JSON.parse(items);
                        } else {
                            items = [];
                        }
                        items.push(item.Name);
                        localStorage['expanded'] = JSON.stringify(items);
                    },
    

    在detailCollapse事件中,将该行记录的id去掉:

                    ds_DetailCollapse: function (e) {
                        var grid = $("#dsgrid").data("kendoGrid");
                        var item = grid.dataItem(e.masterRow);
                        var items = JSON.parse(localStorage['expanded']);
    
                        items = items.filter(function (x) {
                            return x != item.Name;
                        });
    
                        localStorage['expanded'] = JSON.stringify(items);
                    },
    

    在dataBound事件中,展开对应的行:

                   ds_dataBound: function (e) {
                        var row = e.sender.tbody.find("tr.k-master-row").first();
                        var items = localStorage['expanded'];
                        var grid = $("#dsgrid").data("kendoGrid");
                        if (items) {
                            items = JSON.parse(items);
                            items.forEach(function (x) {
                                var item = grid.dataSource.view().find(function (y) {
                                    return y.Name == x;
                                });
                                if (item) {
                                    row = $('#' + grid.element.attr('id') + ' tr[data-uid="' + item.uid + '"]')
                                } 
                            })
                        } 
                        e.sender.expandRow(row);
                        
                    },
    
  • 相关阅读:
    Vue3中父组件与子组件的传值
    Ultralytics(YoloV8)开发环境配置,训练,模型转换,部署全流程测试记录
    leetcode 1268. Search Suggestions System(搜索推荐系统)
    nvm 切换、安装 Node.js 版本
    面试记录1
    CKAN教程之将 Snowflake 连接到 CKAN 以发布到开放数据门户
    记一次清理挖矿病毒的过程
    Qt网络编程的命令模式:把网络命令封装成类
    面试题:Java反射和new效率对比,差距有多大?
    【Java】安装JDK开发者工具包并编写第一个程序“Hello World.java”
  • 原文地址:https://www.cnblogs.com/zhenl/p/15920658.html