表格行内编辑增删改查
前言
最近在做一个OA系统,需要将大量excel中的数据录入,并且希望以后新建数据时,也能像excel那样方便。并且这个后台系统有非常多这样的表单。因此需要做一个内敛的表单控件。
上网找到一款编辑起来非常方便的控件handsontable,这个表单控件可以支持excel中的多种操作,比如多行复制粘贴,ctrl+z撤销,ctr+r重做等等。但是这个插件对数据的提交和数据的校验做的并不好。于是自己对这个插件进一步封装成为一个控件。
写好后的控件演示地址
目标
控件希望至少做到的下几点
- 当某一行有单元格发生变化时,自动校验这一行的数据,如果校验成功,将数据post到一个save url,post能绑定固定参数。
- 当有多行发生变化时,依次校验各行,依次提交校验通过的数据。
- 当最后一行数据发生变化时,不管是否已经提交,都立即在后面追加一行。
- 当保存的行是新建的时候,要将响应的记录ID更新到table上。
- 绑定table.render刷新事件,当刷新时间被触发时,重新渲染列表。
- 绑定add.table_id事件,事件将绑定一行新的数据(由触发的时候传递过来),响应事件时,将这行新的记录追加到表格中。
- 选择多行快速删除,get一个请求传递参数ids(逗号分隔id)
使用
首先看看如何使用这个控件,只需要像下面这样
<?php $data = array('rows' => array(array('id'=>1,'username'=>'lvyahui','email'=>'lvyahui@163.com','phone'=>'9999','group'=>'组1','group_id'=>1),array('id'=>2,'username'=>'lvyahui','email'=>'lvyahui@163.com','phone'=>'9999','group'=>'组2','group_id'=>2),array('id'=>3,'username'=>'lvyahui','email'=>'lvyahui@163.com','phone'=>'9999','group'=>'组1','group_id'=>1),array('id'=>4,'username'=>'lvyahui','email'=>'lvyahui@163.com','phone'=>'9999','group'=>'组3','group_id'=>3),), );?><div id="dataTable"></div> {{HTML::script('js/handsontable.full.min.js')}} {{HTML::style('css/handsontable.full.min.css')}} {{HTML::script('js/editTable.js')}} <script>$('#dataTable').initEdit({rows : JSON.parse('<?=json_encode($data['rows'])?>'),colHeaders : ['ID','用户名','邮箱','电话号码'],columns : {id : {readOnly : true},username : {label : '用户名',required : true,validator : /^\w+$/},email :{required : true,//validator : /^\w+$/ editor: 'select',selectOptions : ['lvyahui8@126.com','lvyahui@163.com']},phone :{validator : function(value,callback){//return value.length > 1; callback(true);return true;},allowVaild : true},group : {required : true,editor: 'select',selectOptions : ['组1','组2','组3']}},bindData : {cus : 1,category_id : 2},beforeSave : function(data){var groups = [{name:'组1',id:1},{name:'组2',id:2},{name:'组3',id:3}];var has = groups.filter(function(item){if(item.name == data.group){return true;}else{return false;}});if(has.length > 0){data.group_id = has[0].id;}return data;},afterSave : function(resp){},url : {save : '<?=URL::to('test/table-row')?>',delete : '<?=URL::to('test/table-delete')?>' }});$('body').trigger('add.dataTable',{id : 111,username : 'lvyahui',email : 'lvyahui@126.com',phone : '100000',gourp_id : 1});</script>
上面的代码体现了设计思路,提交数据的时候,提交的是rows的某一行,显示的时候,只显示columns中有的属性。对于关系型数据,可以在提交数据之前将关系数据绑定提交。最下面触发的add.table_id(之所以事件跟一个table_id是为了保证一个页面有多个这个table的时候不冲突)事件,新增了一条数据。
你就可以看到生成了这样一个表格。
下面以一个实际的例子为例
1 <div class="table" id="editTable"></div> 2 {{HTML::script('js/handsontable.full.min.js')}} 3 {{HTML::style('css/handsontable.full.min.css')}} 4 {{HTML::script('js/editTable.js')}} 5 6 <script> 7 $('#editTable').initEdit({ 8 rows : [<?= implode(",",array_map(function($item){ 9 return "{id:$item->id,serial:'$item->serial',name:'$item->name',store:'$item->store',ship_time:'$item->ship_time',number:$item->number}"; 10 },$model->items->all()));?>], 11 columns : { 12 id : { 13 label : 'ID', 14 readOnly : true 15 }, 16 store : { 17 label : 'PO #', 18 required: true 19 }, 20 serial : { 21 label : '产品ID', 22 required : true 23 }, 24 25 name :{ 26 label : '产品名称', 27 required : true 28 }, 29 30 description: { 31 label : '产品描述', 32 required : false 33 }, 34 35 ship_time : { 36 label : '发货截止时间', 37 required : true 38 }, 39 number : { 40 label : '数量', 41 required : true 42 } 43 }, 44 bindData : { 45 customer_orders_id : '<?=$model->id?>' 46 }, 47 url : { 48 save : '<?=URL::to('customerOrderItem/edit')?>', 49 delete : '<?=URL::to('customerOrderItem/delete')?>' 50 } 51 }); 52 </script>
效果
生成的表单就像这样
下面来批量新建,可以看到但出现两行符合要求是,向后台post了两个请求,请求响应了成功,将ID更新到单元格
修改单元格
触发add.table_id事件,向表格添加一行数据
1 $("body").delegate(".select-item", "click", function (e) { 2 var m = $("#add-product"); 3 $.get($(this).attr('href')+'&type='+$that.data('type'),function(resp){ 4 console.log(resp); 5 resp.number = resp.number || 0; 6 $('body').trigger('add.'+$that.data('table'),resp); 7 m.modal('hide'); 8 },"json"); 9 return false; 10 });
触发刷新
$('.order-item').one('shown.bs.collapse',function(){$('div.edit-table').trigger('table.render'); });
多行删除,这里因为后台还没做,所以会报错,但是数据时请求到了delete url上的
代码
下面是这个控件的核心代码。
1 /* 2 * editTable.js 3 */ 4 ;(function($,global){ 5 6 var objToArray = function(obj){ 7 var arr = []; 8 for(var x in obj){ 9 arr.push(obj[x]); 10 } 11 return arr; 12 }, 13 requiredRender = function(hot, td, row, col, prop, value, cellProperties){ 14 Handsontable.renderers.TextRenderer.apply(this, arguments); 15 td.className += 'required'; 16 //td.style.backgroundColor = 'yellow'; 17 }; 18 19 var ExcelTable = function(element,options){ 20 var that = this; 21 22 this.element = element; 23 this.hot = null; 24 this.edit = null; 25 this.defaults = { 26 bindData : {}, 27 rows : [], 28 url : { 29 save : '', 30 delete : '' 31 }, 32 columns : {}, 33 tableClassName : '', 34 afterSave : function(resp){}, 35 beforeSave : function(data){} 36 }; 37 38 this.options = $.extend({},this.defaults,options); 39 this.rows = this.options.rows; 40 //this.cols = objToArray(that.options.columns); 41 var colHeaders = [], 42 columns = []; 43 for(var x in this.options.columns){ 44 if(this.options.columns[x].hasOwnProperty('label')){ 45 colHeaders.push(this.options.columns[x].label); 46 }else{ 47 colHeaders.push(x); 48 } 49 columns.push($.extend({data:x},this.options.columns[x])); 50 } 51 this.cols = columns; 52 var hotOptions = { 53 data : options.rows, 54 colHeaders : colHeaders, 55 afterChange : function(changes,source){ 56 if(source !== 'loadData'){ 57 that.save(changes); 58 } 59 }, 60 beforeRemoveRow:function(index,amount){ 61 that.delete(index,amount); 62 }, 63 columns : columns , 64 minSpareRows: 1, 65 contextMenu: ['remove_row'], 66 cells: function (row, col, prop) { 67 if(col < that.cols.length && that.cols[col].required){ 68 this.renderer = requiredRender; 69 } 70 }, 71 tableClassName : this.options.tableClassName, 72 width : '100%', 73 stretchH: "all", 74 colWidths : this.options.colWidths 75 }; 76 77 if(typeof Handsontable === "function"){ 78 this.hot = new Handsontable(this.element,hotOptions); 79 } 80 81 $('body').bind('add.'+$(element).attr('id'),function(e,row){ 82 that.rows.splice(that.rows.length-1,0,row); 83 that.hot.render(); 84 }); 85 $(element).bind('table.render',function(){ 86 that.hot.render(); 87 }); 88 }; 89 90 ExcelTable.prototype = { 91 constructor : ExcelTable, 92 post : function(data){ 93 var that = this; 94 var ret = this.options.beforeSave(data); 95 if(typeof ret === "object"){ 96 data = ret; 97 } 98 if(data.id){ 99 data.action = 'edit'; 100 }else{ 101 data.id = ''; 102 data.action = 'edit'; 103 } 104 if(this.options.url.save){ 105 $.post(this.options.url.save,data,function(resp){ 106 if(!data.id && resp.id !== null){ 107 // 新建了记录,重新渲染 108 that.options.rows[resp.index].id = resp.id; 109 that.hot.render(); 110 } 111 that.options.afterSave(resp); 112 },'json'); 113 } 114 }, 115 getDelete : function(ids){ 116 if(this.options.url.delete){ 117 $.get(this.options.url.delete+'?id='+ids,function(resp){ 118 119 }); 120 } 121 }, 122 save : function(cells){ 123 var that = this, 124 rows = []; 125 cells.forEach(function(cell){ 126 if(cell[2] !== cell[3]){ 127 rows[cell[0]] = cell[0]; 128 } 129 }); 130 rows.forEach(function(rowIndex){ 131 var row = that.rows[rowIndex], 132 data = $.extend(row,that.options.bindData); 133 data.index = rowIndex; 134 if(that.validate(row)){ 135 console.log(data); 136 that.post(data); 137 } 138 }); 139 }, 140 delete : function(start,amount){ 141 var ids = []; 142 for(var x = start;x < start + amount;x++){ 143 ids.push(this.rows[x].id); 144 } 145 this.getDelete(ids.join(',')); 146 }, 147 validate : function(row){ 148 var that = this; 149 return that.cols.filter(function(col,index){ 150 if(row.hasOwnProperty(col.data)){ 151 var valitator = that.hot.getCellValidator(0,index); 152 if(col.required){ 153 if(!row[col.data]) return true; 154 if(valitator){ 155 return !that.execValidator(valitator,row[col.data]); 156 } 157 return false; 158 }else if(row[col.data] && valitator){ 159 return !that.execValidator(valitator,row[col.data]); 160 }else{ 161 return false; 162 } 163 } 164 else{ 165 return false; 166 } 167 }).length == 0; 168 }, 169 execValidator:function(validator,value){ 170 if(validator instanceof RegExp === true){ 171 return validator.test(value); 172 }else if(typeof validator === "function"){ 173 return validator(value,function(){}); 174 }else{ 175 return false; 176 } 177 }, 178 179 isEmptyRow : function(rowIndex){ 180 var rowData = this.hot.getData()[rowIndex]; 181 182 for (var i = 0, ilen = rowData.length; i < ilen; i++) { 183 if (rowData[i] !== null) { 184 return false; 185 } 186 } 187 return true; 188 } 189 }; 190 191 $.fn.initEdit = function(options){ 192 return this.each(function(){ 193 var excelTable = new ExcelTable(this,options); 194 }); 195 } 196 197 })($ || jQuery,window);
转载于:https://www.cnblogs.com/lvyahui/p/4891483.html
表格行内编辑增删改查相关推荐
- bootstrap table 表格支持shirt 多选_bootstrap-table 表格行内编辑实现
这篇文章向大家介绍一下如何使用bootstrap table插件实现表格的行内编辑功能. 我的web前端学习交流群点击进入1045267283,欢迎加入! 先放一张效果图: 应用场景 之前的项目也是采 ...
- python测试开发django-173.bootstrap实现table表格行内编辑
前言 网上看了很多基于bootstrap的table表格行内编辑,需要基于bootstrap-table,bootstrap-table-edit,x-editable等插件,写的很复杂. 我想实现的 ...
- Datatables实现表格行内编辑功能
表格行内编辑功能通过操作DOM来实现,最终实现效果如下代代码 html <table class="table table-striped table-bordered table-h ...
- datatables表格行内编辑的实现
Datatables是一款jquery表格插件,它是一个高度灵活的工具,灵活就意味着很多功能需要自己去实现,比如说行内编辑功能. Datatables自己是没有行内编辑功能的,最简单的是通过modal ...
- oracle SQL 命令行(三.增删改查)
SQL> select * from stu;SON SNAME SAGE -------- -------------------- ---------- 1001 张三 18 1003 李四 ...
- 使用ABSL(ABAP Script Language)完成SAP Cloud for Customer里Customer Quote以及行项目的增删改查
The user roles are Studio Administrator, Developer, and Business User. PDI_ADMINISTRATION / Administ ...
- editable组件_表格行内编辑事件
1.简介 x-editable组件是一个适用于bootstrap(目前只更新到bootstrap3),jquery,jquery UI三种风格样式的弹出框编辑插件.本文根据项目需求主要介绍它在boot ...
- Mysql —— C语言链接mysql数据库,命令行形式(getopt()函数),用户、用户组增删改查(用户组表内有用户控制的策略字段)
函数说明--getopt(): 函数说明 getopt()用来分析命令行参数.参数argc和argv分别代表参数个数和内容,跟main()函数的命令行参数是一样的. optstring中的指定的内容的 ...
- vue+element实现树状表格的增删改查;使用el-table树形数据与懒加载实现树状表格增删改查
以下代码可以直接复制使用 一.情景: 列表是一个树状表格,可以无限添加下级,以及对列表的某一行进行增删改查(目前查没有写). 原博链接 二.本篇是在原博主的代码基础上添加了部分功能. 功能1: 给树状 ...
最新文章
- C# typeof Gettype is as 拆箱 装箱
- torch拼接合并 cat优化记录
- C++代码片段(四)萃取模板类的模板参数类型
- httpclient封装获取响应实体_Httpclient 接口自动化
- mysql与citespace_CiteSpace与MySQL数据库的连接-科学网—博客.PDF
- 地方政府大数据发展的现实与理想
- 32位与64位、单精度(single-precision)与双精度(double-precision)
- linux内存——/proc/sys/vm/drop_caches
- python的集合类型_python集合类型
- tensorflow支持python3.7吗_前端开发行业真的会被AI取代吗?
- 您知道数据中心的最佳温度是多少吗?
- 手机输入法,谁能笑到最后?
- 微信小程序样式-id选择器的使用教程
- 笔迹心理学(2): 功能设计
- 北京程序员小哥哥的故事
- 热门好用的二维码生成器API
- 克隆虚拟机后无法连接网络的问题
- Mothur5进阶_Mothur扩增子基因序列分析_基于OTU或ASV的多样性指数分析
- token令牌的含义和操作
- 华为鸿蒙os对比安卓系统,华为手机鸿蒙OS 2.0、EMUI 11界面对比:安卓底层没了
热门文章
- c语言模拟java面向对象_面向对象设计模式C语言实现.PDF
- 三极管工作原理_4种集电极-基极负反馈式三极管偏置电路的工作原理分析
- spring boot-The temporary upload location [ ] is not valid
- 【thymeleaf】th:text、[[]]、th:utext、[()]输出变量
- maven 引入net.sf.json-lib依赖时报错(classifier)
- java join yield_java中join和yield有什么区别?
- 图片怎么等比缩放_mac图像缩放工具Teorex iResizer
- ios 持续获取定位 高德地图_概述-iOS 定位SDK | 高德地图API
- php代码实现对word文件的查找与替换,ThinkPHP5使用phpword实现文件模板字符替换
- linux如何判断光盘是否挂载,LInux下如何挂载光盘找rpm包的方法步骤