4

Kendo UI Grid 批量编辑使用总结 - 寻找无名的特质

 2 years ago
source link: https://www.cnblogs.com/zhenl/p/15920658.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

项目中使用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 + '">​</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);
                    
                },

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK