Chinaunix首页 | 论坛 | 博客
  • 博客访问: 371051
  • 博文数量: 28
  • 博客积分: 455
  • 博客等级: 下士
  • 技术积分: 445
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-09 11:10
文章分类

全部博文(28)

文章存档

2016年(5)

2014年(1)

2013年(10)

2011年(7)

2010年(5)

我的朋友

分类: jQuery

2013-09-02 00:06:59

一、
在使用easyui插件的时候,发现datagrid的官方(
demo都是针对某一个功能来进行讲解
比如我们最常用的datagrid的form编辑功能几乎没提到
不过呢,在官网demo主页的第一个例子,就是Application下的 
Basic CRUD Application 就是一个form编辑的案例
需要自己创建一个dialog来做form的提交

而datagrid的行编辑功能在datagrid的例子
Row Editing in DataGrid里面
也讲的比较完整了,只是缺少了和服务器端交互的部分


二、
使用了多个表格插件之后,个人觉得jqGrid这个插件相对来说是比较强大的(http://www.trirand.com/blog/)
不论是行编辑还是form编辑,而且各种配置参数也是非常详尽,开发者能想到的几乎都涵盖了进去

三、现状是
使用easyui插件开发了一个网站,左侧是菜单,点击不同的菜单,在主页面就显示一个tab页面
而每个tab页面里边都有一个有待管理的datagrid,datagrid的编辑方式采用行编辑模式


此时如果照着官网的demo来为每个tab页面的datagrid写代码,显然有太多的重复工作
并且,由于多个tab页面添加进来以后,实际是都是在同一个页面上显示,还需要考虑每个datagrid之间不能有代码冲突的问题
例如,官网的行编辑例子里面第一句代码 
  1. var editIndex = undefined;
定义的当前编辑行行号,这个就必须为每一个datagrid定义一个不同的变量
好,为了解决这些问题,在官网例子的基础上,开始改造一个更通用的代码

四、准备工作
首先主页的的样式和用到的js文件,需要引入
其中用到的json插件,主页
用于把javascript对象转换成json字符串,用法就是$.toJSON(object);
方便于传递给服务器端

为了提供好的用户体验,在点击了保存按钮时,显示一个“正在保存”的提示,并且阻止用户多次提交
我们在主页面上放上一个window(从官方demo里面拿来修改了一点点)
等待保存时显示出来

点击(此处)折叠或打开

  1. <div id="w" class="easyui-window" title="请稍候..."
  2.     data-options="modal:true,closed:true,closable:false,minimizable:false,maximizable:false,iconCls:'icon-save'"
  3.     style="width:200px;height:80px;padding:10px;">
  4.         保存中,请不要刷新页面
  5. </div>

五、开始修改官方代码
胡乱新建一个js文件,就叫什么easyui-row-edit.js

1、 修改 var editIndex = undefined;

点击(此处)折叠或打开

  1. // 定义一个全局对象,存放不同tab页面中各个datagrid对应的当前行号
  2. // 而下面的所有方法,都加了一个参数: indexKey ,每个datagrid取一个唯一的key传进来即可
  3. // 例如,菜单管理传入参数'menu',代码管理传入参数'code'
  4. // 这样 editIndex = { menu: 10, code: 15 } 就能清晰地分别开每个datagrid当前行了
  5. var editIndex = {};

2、 修改 function endEditing

点击(此处)折叠或打开

  1. // 判断目前在编辑的行是否可结束编辑
  2. // 主要是对各输入字段的校验(字段的校验规则在初始化datagrid时指定)
  3. // parameters: datagridId(datagrid的id,例如'#dg',注意前面加星号)
  4. // indexKey (该datagrid当前编辑行在对象editIndex中的key)
  5. // return: 通过校验返回true,否则false
  6. // 本方法提供给以下其他方法调用
  7. function endEditing( datagridId, indexKey ){
  8.     console.log(editIndex);
  9.     if (editIndex[indexKey] == undefined){return true;}    // 当前没有编辑的行直接返回true
  10.     if ($(datagridId).datagrid('validateRow', editIndex[indexKey])){ //校验通过
  11.         $(datagridId).datagrid('endEdit', editIndex[indexKey]);        // 完成编辑
  12.         editIndex[indexKey] = undefined;
  13.         return true;
  14.     } else {
  15.         return false;        //未通过校验
  16.     }
  17. }

3、修改function onClickRow

点击(此处)折叠或打开

  1. // 点击数据行的时候所做的操作
  2. // parameters: datagridId(datagrid的id,例如'#dg',注意前面加星号)
  3. // index: 当前点击的行
  4. // indexKey (该datagrid当前编辑行在对象editIndex中的key)
  5. // 使用方法: $('#dgCode').datagrid({
  6. //onClickRow: function(index){
  7. // onClickRow('#dgCode', index ,'code');
  8. //}
  9. //});
  10. function onClickRow(datagridId, index, indexKey){
  11.     if (editIndex[indexKey] != index){    // 点击的行和当前编辑的行不一样时
  12.         if (endEditing( datagridId, indexKey )){    // 当前编辑的行可结束编辑时
  13.             $(datagridId).datagrid('selectRow', index) // 选中当前点击行
  14.                     .datagrid('beginEdit', index);     // 并开始编辑
  15.             editIndex[indexKey] = index;                            // 当前编辑行变成点击的行
  16.         } else {    // 当前编辑行不可结束
  17.             $(datagridId).datagrid('selectRow', editIndex[indexKey]); // 继续留在当前编辑的行
  18.         }
  19.     }
  20. }

4、修改 function append

点击(此处)折叠或打开


5、修改function removeit

6、修改function accept

点击(此处)折叠或打开

  1. // 保存更改
  2. // parameters: datagridId(datagrid的id,例如'#dg',注意前面加星号)
  3. // indexKey (该datagrid当前编辑行在对象editIndex中的key)
  4. // url ( 保存的url )
  5. // ids 主键字段(可选)
  6. // 考虑到数据行数据量可能较大,当删除的时候,其实服务器端只需要知道主键即可
  7. //                 为了减轻网络压力,前端只传递删除的主键数组即可
  8. // 1、单主键的情况,参数传入字符串,例如是'id',此时传递到服务器端的就是一个id数组:['44445','4444','3333','1002']或者['usera','userb','userc','userd']
  9. // 2、组合字段做主键时,参数传入数组,例如['userid','mobile'],传递到服务器端的就是一个对象数组:[{userid:'usera',mobile:'135'},{userid:'userb',mobile:'136'}]
  10. // 3、不传入参数,或者传入任何返回false的表达式,删除数据依然把整条数据传递给服务器端
  11. // 使用方法: 点击保存按钮时调用
  12. // 例如: 保存
  13. function accept( datagridId, indexKey, url, ids ){
  14.     // 还是先判断是否可结束编辑才能继续保存
  15.     if ( !endEditing( datagridId , indexKey) ) return;
  16.     // 判断一下,没有更改,则不用保存
  17.     if ( $(datagridId).datagrid('getChanges').length === 0 ) return;
  18.     
  19.     // 分别获得新增行、删除行、更改行的数据    
  20.     var inserted = $( datagridId ).datagrid('getChanges','inserted');
  21.     var deleted = $( datagridId ).datagrid('getChanges','deleted');
  22.     var updated = $( datagridId ).datagrid('getChanges','updated');
  23.     var deletedId = [];        //
  24.     if ( ids ) { // 设置了主键字段,才重新组装删除行的数据
  25.         if ( $.isArray(ids) ) { // 组合主键的,只返回包含组合主键和值的对象
  26.             deletedId = $.map( deleted, function(row ){
  27.                 var newRow = {};
  28.                 $.each( ids,function(idx, id){
  29.                     newRow[id] = row[id];
  30.                 });
  31.                 return newRow ;
  32.             });
  33.         } else { // 只有一个主键字段的,只返回主键的值,连主键都不用返回
  34.             deletedId = $.map( deleted, function(row ){
  35.                 return row[ids] ;
  36.             });
  37.         }
  38.     } else {
  39.         deletedId = deleted;
  40.     }
  41.     
  42.     $('#w').window('open');
  43.     
  44.     $.ajax({
  45.         url: url,
  46.         dataType: 'json',
  47.         method: 'POST',
  48.         data : {
  49.             inserted: $.toJSON(inserted),
  50.             updated: $.toJSON(updated),
  51.             deleted: $.toJSON(deletedId)
  52.         }
  53.     }).done(function(data){
  54.         if (data.status === 'OK') { // 提交成功
  55.             $(datagridId).datagrid('acceptChanges');
  56.             $(datagridId).datagrid('reload'); // 刷新datagrid
  57.         }
  58.         
  59.     }).fail(function(resp){
  60.         $.messager.alert('出错了',resp.responseText);
  61.     }).always(function(){
  62.         $('#w').window('close');
  63.     });
  64. }

7、修改function reject

六、
主页面引入该文件easyui-row-edit.js
好啦,不同的tab页面只要简单调用即可,例如“代码管理”tab页面的datagrid和toolbar是这样子

点击(此处)折叠或打开

  1. <table id="dgCode" title="系统代码列表" style="width:850px;height:auto"
  2.             toolbar="#toolbarCode" pagination="true" idField="id"
  3.             rownumbers="true" fitColumns="true" singleSelect="true" striped="true"
  4.             data-options="" pageSize="20">

点击(此处)折叠或打开

  1. <div id="toolbarCode">
  2.         <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-add',plain:true" onclick="append('#dgCode','code');">新增</a>
  3.         <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-remove',plain:true" onclick="removeit('#dgCode','code');">删除</a>
  4.         <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-save',plain:true" onclick="accept('#dgCode','code','manager/system/commit_code','id');">保存</a>
  5.         <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-undo',plain:true" onclick="reject('#dgCode','code');">撤销更改</a>
  6.     </div>
并且加一小段javascript代码

点击(此处)折叠或打开

  1. <script type="text/javascript">
  2.     editIndex['code'] = undefined;
  3.     $(function(){
  4.         $('#dgCode').datagrid({
  5.             url: 'manager/system/get_code_list',
  6.             onClickRow: function(index){
  7.                 onClickRow('#dgCode', index ,'code');
  8.             }
  9.         });
  10.     });
  11. </script>

而“菜单管理”tab页面只需要把上面的代码黑色+下划线部分修改一下即可
并且把两个url修改一下,分别获取菜单列表和提交更改的url

点击(此处)折叠或打开

  1. <table id="dgMenu" title="菜单列表" style="width:700px;height:auto"
  2.             toolbar="#toolbarMenu" pagination="true" idField="id"
  3.             rownumbers="true" fitColumns="true" singleSelect="true" striped="true"
  4.             data-options="" pageSize="20">

点击(此处)折叠或打开

  1. <div id="toolbarMenu">
  2.         <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-add',plain:true" onclick="append('#dgMenu', 'menu');">新增</a>
  3.         <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-remove',plain:true" onclick="removeit('#dgMenu', 'menu');">删除</a>
  4.         <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-save',plain:true" onclick="accept('#dgMenu','menu','manager/system/commit_menu','id');">保存</a>
  5.         <a href="javascript:void(0)" class="easyui-linkbutton" data-options="iconCls:'icon-undo',plain:true" onclick="reject('#dgMenu', 'menu');">撤销更改</a>
  6.     </div>

点击(此处)折叠或打开

  1. <script type="text/javascript">
  2.     editIndex['menu'] = undefined;
  3.     $(function(){
  4.         $('#dgMenu').datagrid({
  5.             url: 'manager/system/get_menu_list',
  6.             onClickRow: function(index){
  7.                 onClickRow('#dgMenu', index, 'menu' );
  8.             }
  9.         });
  10.     });
  11. </script>

新增加的tab页面以此类推即可,简化了工作流程

七、服务器端的处理
我使用的是php的codeigniter框架,在controller这样处理

点击(此处)折叠或打开

  1. function commit_menu(){
  2.         $inserted = isset($_POST['inserted']) ? json_decode( $_POST['inserted'], true ) : false;
  3.         $updated = isset($_POST['updated']) ? json_decode( $_POST['updated'], true ) : false;
  4.         $deleted = isset($_POST['deleted']) ? json_decode( $_POST['deleted'], true ) : false;
  5.         
  6.         $this->load->model('system_model');
  7.         if ( $inserted ) {
  8.             $this->system_model->insertMenus($inserted);
  9.         }
  10.         if ( $updated ) {
  11.             $this->system_model->updateMenus($updated);
  12.         }
  13.         if ( $deleted ) {
  14.             $this->system_model->deleteMenus($deleted);
  15.         }
  16.         
  17.         $result['status'] = 'OK';
  18.         $this->output
  19.             ->set_content_type("application/json")
  20.             ->set_output( json_encode( $result));
  21.     }

在model层的处理就更简单了,使用Active Record的批量提交

点击(此处)折叠或打开

  1. function insertMenus ( $rows ){
  2.         $this->db->insert_batch(TABLE_SYSTEM_MENU, $rows);
  3.     }
  4.     
  5.     function updateMenus ( $rows ){
  6.         $this->db->update_batch(TABLE_SYSTEM_MENU, $rows,'id');
  7.     }
  8.     
  9.     function deleteMenus ( $ids ) {
  10.         foreach($ids as $id) {
  11.             $this->db->delete(TABLE_SYSTEM_MENU, array('id' => $id));
  12.         }
  13.     }
其实,如果提交的处理都大同小异的话,在php后台也可以把这块功能单独写成通用的函数
只要传入不同的表名即可处理,这个就简单了,不做赘述。

补充一点:
由于刚使用easyui插件,很多方面处于摸索阶段,都是依靠官方的api文档
而api文档有的地方其实讲的不是很清楚,难免走了很多弯路

在使用行编辑功能的时候,有的字段不允许编辑,
比如说创建时间,后台自动生成,前台不允许编辑
试了很多方法没搞成,最后才发现,只要在初始化这个字段的时候,"editor"不设置即可,就是这么简单




阅读(15136) | 评论(1) | 转发(1) |
给主人留下些什么吧!~~

minrongna2014-07-24 10:33:59

文明上网,理性发言...