jquery:将table表变为可编辑状态,记录修改,新增或者删除的行。传入后台controller中

本文介绍了一个使用jQuery实现的可编辑HTML表格案例,该案例允许用户直接在表格内修改数据,并支持新增、删除等功能,最终通过AJAX将更改的数据批量提交到服务器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


博主初次入行,遇到一个好玩的客户需求,自己用jquery调试了好久总算调出来了,这里给大家分享一下我的经验,新手!新手!新手!重要的事多说一遍:新手!这个好玩的需求在于对html table中数据操作问题,大多数情况下点新增,编辑按钮时都是弹出壹个新网页,在网页中进行操作,这如果在一次需要对数据库表做很多的修改就显得很鸡肋;所以客户更希望直接在table表中修改数据,然后再一次性将数据发送到后台处理。

因为是自己一步一步的调出来的,所以可能看着有些菜,毕竟博主还是新手,有不对不好的地方还请帮帮忙赐教赐教

第一步:需求分析

把table表变成可编辑状态,无非就是放一个input到相应的td中;
首先第一需要知道的要编辑的是哪一行:可以对每一个行讲一个onclick事件
其次就是要保证一次正在编辑的只有一行,所以点击一行时需要清除前一行的input格式以及判断为空时就不能点击
最后就是记录是新增的行,还是修改的行,以及删除的行

第二步:网页

就是一张普通的jsp页面,用foreach遍历出所有的数据到table表中:
<c:forEach items="${result.data}" var="item" varStatus="s">				
			 	<tr class="tr_change" onclick="_edit(this)">
			 		<input type="hidden" value="${item.id}"/>
 	 		 		 <td name="name"> ${item.name}</td>
		 	 	</tr>   
		</c:forEach>
得到一张这样的表(为了方便,我就只贴了一列的表):

然后大概效果(瞎做的gif图,意思意思):

然后就是js代码了:
首先加一个temp变量判断是否对table编辑过:
var temp = true;
//tr点击编辑事件
		function _edit(obj){
			var has = $(".table input[type=text]");
			var could = $(obj).find(":input[type=text]");
			//判断当前tr是否正在编辑
			if(could.length!=0){
				return;
			}
			//判断table中在编辑的tr是否为空
			if($(has).val()==""){
				return;
			}
			_clear(has);
			$(obj).children("td").html("<input onchange='_change(this,"+'"'+$(obj).children("td").html()+'"'+")' type='text' value='"+$(obj).children("td").html().trim()+"'>");
		}
		//清除input格式
		function _clear(obj){
			var parent = $(obj).parent();
			var val = $(obj).val();
			if(val != ""){
			$(parent).html(val);}
			else
				return;
		}
现在可以对已有的数据进行修改;然后要解决的是新增和删除:
//新增
		function toAdd(){
			var could = $(".table input[type=text]");
			if($(could).val()!=""){
				_clear(could);
			 	$("table.table").append("<tr class='tr_change addRow' onclick='_edit(this)'><input type='hidden' value='0'/><td><input type='text' onchange='_change(this,"+''+")' value=''/></td></tr>");
			}else{
				return; 
			}
		} 
		//删除
		function _delete(){
			var has = $(".table input[type=text]");
			if(has.length != 0){
				var deleteid = $(has).parent().parent().find("input[type=hidden]").val();
				if(deleteid!="0"){
					deletejson += "," + deleteid;
					temp = false;
				}
					$(has).parent().remove();
			}
 		}
当然刷新按钮依旧:
//刷新
		function _refresh(){
					window.location.reload();
		}
然后再对onchange事件进行编辑,这里我们可以小小的添加一次使table数据都是唯一的判断:
//记录修改与否
		function _change(obj,preval){
			var val = $(obj).val(); 
			$("table").find("td").each(function(){
				if(val.trim()==$(this).html().trim()){
					alertF("不能有重复的值,修改失败");
					$(obj).val(preval);
				}else{
					var updateid = $(obj).parent().parent().find("input[type=hidden]").val();
					if(updateid != "0"){
						$(obj).parent().parent().addClass("updateRow");
					}
					temp = false;
				}
			});
		}
这里对于新增的行我们加一个class为addRow,对修改的行加一个class为updateRow;用去区分json;

第三步:对table表中的数据封装json传入后台中

就是对保存按钮的点击事件:
var deletejson = "";
var addjson = "[";
var updatejson = "[";
//保存
		function _save(){
			if(temp == true){
				alertF("没有任何修改过的数据,无需保存");
				return;
			}
			if($(".table input[type=text]").val()==""){
				return;
			}
			_clear($(".table input[type=text]"));
			//拼接新增的行的json对象
			var addtab = $("table").find("tr.addRow");
			if(addtab.length>0){
				for(var i=0;i<addtab.length;i++){
					addjson += 
								 '{"typename":"' +addtab.eq(i).find("td").html().trim()+ '"},';
				}
				addjson = addjson.substr(0,addjson.length-1);
				addjson += "]";
        		addjson = eval("("+addjson+")");
			}
			//拼接修改的行的json对象
			var updatetab = $("table").find("tr.updateRow");
			if(updatetab.length>0){
				for(var i=0;i<updatetab.length;i++){
					updatejson += '{"topictype":"'+updatetab.eq(i).find("input[type=hidden]").val()
								+ '","typename":"' +updatetab.eq(i).find("td").html().trim()+ '"},';
				}
				updatejson = updatejson.substr(0,updatejson.length-1);
				updatejson += "]";
				updatejson = eval("("+updatejson+")");
			}
			if(deletejson.indexOf(",")==0){
					deletejson = deletejson.substr(1,deletejson.length-1);
			}
			 /* $.ajax({
				url:url,
				type:"post",
				dataType:"json",
				data:{updateJson:JSON.stringify(eval("("+updatejson+")")),
					  addJson:JSON.stringify(eval("("+addjson+")")),
					  deleteJson:deletejson
				},
				success:function(data){
					if(data.responseText == "ok"){
					window.location.reload();
					}
				}
			}) */ 
			$.post(url,{updateJson:JSON.stringify(updatejson),
				  addJson:JSON.stringify(addjson),
				  deleteJson:deletejson},function(data){
					  if(data == "ok"){
							window.location.reload();
					}							
			});
 		} 
这里因为删除其实where语句可以直接用where id in();所以我们直接在删除就封装好json字符串,不用穿对象过去了;

最后:对数据进行数据库回写

其实也没啥好说的,主要就是事务管理这一块,我们都知道,只要进行了两条以上的数据库修改都应该加上事务,统一commit或者rollback
大部分我们都在service层中都配置了事务管理,但是其实不同的需求会有不同的分析,正如这样的客户需求,我们确实就应该在业务层进行事务管理
对于事务这一块我也不咋会,不过经过百度;我找到一个很好的办法事务管理:
我先贴一下原博主的贴:http://blog.youkuaiyun.com/quwenzhe/article/details/60308999
@Resource
	private PlatformTransactionManager transactionManager;
/**
	 * 保存
	 * @param model
	 * @param req
	 * @return
	 * @throws Exception 
	 */
	@RequestMapping(value="doSave" )
	@ResponseBody
	public String doSave(Model model,HttpServletRequest req) throws Exception{ 
		
		DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
	    defaultTransactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
	    TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition);
		try{
		String deletejson = req.getParameter("deleteJson");
		Object addjson = req.getParameter("addJson");
		Object updatejson = req.getParameter("updateJson");
		//删除
		if(deletejson!=null && deletejson.length()>0){
			param = getHashMap();
			param.put("ids", deletejson);     
	 		commonService.delete("deleteTopicType", param);
		}
		//修改
		if(updatejson!=null && updatejson.toString().startsWith("[")){
			List<TopicTypeInfo> list = JSONArray.parseArray(updatejson.toString(), TopicTypeInfo.class);
			for(TopicTypeInfo info : list){								
				topicTypeService.updateTopicType(info);
			}
		}
		//增加
		if(addjson!=null && addjson.toString().startsWith("[")){
			List<TopicTypeInfo> list = JSONArray.parseArray(addjson.toString(), TopicTypeInfo.class);
			for(TopicTypeInfo info : list){
				topicTypeService.addTopicType(info);
			}
		}
		
		transactionManager.commit(status);
		}catch(Exception e){
			transactionManager.rollback(status);
	        e.printStackTrace();
		}
		return "ok";
	}













<think>好的,我现在要解决用户在RuoYi框架中使用Bootstrap Table实现父子关系数据展示的问题。首先,我需要回忆一下RuoYi和Bootstrap Table的相关知识。RuoYi是一个基于Spring Boot的权限管理系统,而Bootstrap Table是一个强大的格插件,支持多种数据展示方式,包括子。 用户的问题是关于如何在RuoYi中实现父子结构的数据展示,也就是主和子的联动。根据提供的引用内容,特别是引用[2]中的官方示例链接,Bootstrap Table自身是支持子格的,可以通过配置detailView选项来展开显示子。此外,引用[4]提到了主子提交的一些前端操作,比如内编辑、添加子删除等,这些可能对实现功能有帮助。 接下来,我需要考虑RuoYi框架中如何集成Bootstrap Table。通常,RuoYi的前端部分使用Thymeleaf模板引擎,结合jQuery和Bootstrap。因此,用户需要在HTML中引入Bootstrap Table的相关CSS和JS文件,然后在JavaScript中初始化格,并配置子的选项。 具体步骤可能包括: 1. 后端准备数据:需要提供一个接口返回主数据,每个主项包含子数据的数组或嵌套对象。 2. 前端初始化主:使用Bootstrap Table的detailView配置,当用户点击展开时,触发查询子数据的函数。 3. 子渲染:在detailFormatter回调函数中,初始化子,并传入对应的子数据。 4. 样式调整:确保子的样式正确,比如缩进、边框等,可能需要参考引用[4]中的样式设置。 需要注意的是,引用[3]提到了类加载器的结构,但可能和前端实现无关,可以暂时忽略。引用[1]和引用[2]提供了Bootstrap Table的示例资源,可能需要查阅这些示例来确保配置正确。 此外,用户可能需要处理子的动态操作,比如添加、删除,这可以参考引用[4]中的相关代码,使用内编辑和事件绑定来实现。提交数据时,后端接收的结构也需要对应主和子的嵌套关系,如引用[4]中的后端数据结构所示。 最后,确保回答结构清晰,分步骤说明,并附上代码示例,同时引用相关的参考资料,比如官方示例和站内引用,帮助用户进一步查阅。</think>### RuoYi框架中使用Bootstrap Table实现父子展示的步骤 #### 1. 后端数据准备 需要构造包含主子嵌套结构的JSON数据。例如: ```json [ { "id": 1, "name": "主1", "subList": [ {"subId": 101, "subName": "子项1"}, {"subId": 102, "subName": "子项2"} ] } ] ``` 后端接口需返回该结构,并在Controller中处理数据映射[^4]。 #### 2. 前端格初始化 在HTML中定义主容器,并初始化Bootstrap Table: ```html <table id="mainTable" data-toggle="table"></table> ``` JavaScript配置主参数: ```javascript $('#mainTable').bootstrapTable({ url: '/main/data', // 主数据接口 detailView: true, // 启用子展开功能 detailFormatter: function(index, row) { return '<table id="subTable_' + index + '"></table>'; }, onExpandRow: function(index, row, $detail) { initSubTable('#subTable_' + index, row.subList); // 初始化子 } }); ``` #### 3. 子初始化函数 定义子渲染逻辑,注意缩进样式与主对齐: ```javascript function initSubTable(selector, data) { $(selector).bootstrapTable({ data: data, columns: [{ field: 'subId', title: '子ID' }, { field: 'subName', title: '子名称' }], // 子样式调整 classes: 'table-no-bordered', onPostBody: function() { $(this).closest('.detail-view').css('padding-left', '40px'); } }); } ``` 此代码参考了Bootstrap Table主子示例的交互逻辑[^2]。 #### 4. 动态操作数据 通过事件绑定实现子增删操作: ```javascript // 添加子 $('#btnAddSub').click(function() { const index = $('#mainTable').bootstrapTable('getSelections')[0].index; $('#subTable_' + index).bootstrapTable('insertRow', {index: 0, row: {subId: '', subName: ''}}); }); // 删除 $('#btnDelSub').click(function() { const mainIndex = ...; // 获取主下标 const subIndex = $('#subTable_' + mainIndex).bootstrapTable('getSelections')[0].index; $('#subTable_' + mainIndex).bootstrapTable('removeRow', subIndex); }); ``` 具体实现可参考内编辑的操作模式[^4]。 #### 5. 数据提交处理 提交时需合并主子数据: ```javascript $('#btnSubmit').click(function() { const mainData = $('#mainTable').bootstrapTable('getData'); mainData.forEach(row => { row.subList = $('#subTable_' + row.index).bootstrapTable('getData'); }); $.post('/submit', {data: mainData}); }); ``` 后端接收的实体类应包含`List<SubEntity> subList`字段。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值