目录
2、触发bootstrap-table-editor中的onEditorSave方法将更改数据添加进数组中
一、业务场景
目前做的的项目中,要求所有列表页的每个单元格可以就地编辑,并且能完成整页的修改。
二、分析问题
该功能有两个难点,第一个是实现单元格的就地编辑,第二个是保存该页修改的值并提交。
三、bootstrap实现就地编辑
1、使用x-editable
简介
x-editable是一个通用的编辑能力组件,可以给任何元素都加上编辑能力,功能强大,可以编辑文本,数字,选项,时间等等各种类型的数据。但是x-editable有一个比较不好的地方,x-editable的编辑模式是弹框的形式,如下图所示:
使用
- 引包
首先下载基于bootstrap的源码到本地。引用相关文件。需要引入的文件有:bootstrap-editable.css、bootstrap-editable.js、bootstrap-table-editable.js
<link href="/plugin/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<link href="/plugin/bootstrap3-editable/css/bootstrap-editable.css" rel="stylesheet" />
<script src="plugin/Scripts/jquery-1.9.1.min.js"></script>
<script src="/plugin/bootstrap/js/bootstrap.min.js"></script>
<script src="/plugin/bootstrap3-editable/js/bootstrap-editable.js"></script>
- 编写页面元素
<a href="#" id="username" data-type="text" data-title="用户名">用户名</a>
- js初始化
$(function () {
$('#username').editable();
});
2、使用bootstrap-table-editor
简介
这是网上一个大佬写的行内编辑组件,可直接更改单元格而不出现弹框,js代码如下:
/**
* author: netcy
*/
!function ($) {
'use strict';
const getItemField = $.fn.bootstrapTable.utils.getItemField;
const calculateObjectValue = $.fn.bootstrapTable.utils.calculateObjectValue;
function createTextEditor(){
const editor = $('<input class = "form-control"></input>');
editor.css("width",`100%`);
return editor;
}
function createNumberEditor(){
var editor = $('<input class = "form-control"></input>');
editor.attr('type', 'number');
editor.attr('step', '0.1');
editor.css("width",`100%`);
return editor;
}
function createSelectEditor(){
var select = $('<select class="form-control"></select>');
return select;
}
const textEditor = createTextEditor();
const numberEditor = createNumberEditor();
const editorCache = {
text:textEditor,
number:numberEditor,
select:createSelectEditor(),
};
$.extend($.fn.bootstrapTable.defaults, {
editable: false,
reInitOnEdit:true,
onEditorInit: function () {
return false;
},
onEditorSave: function (field, row, oldValue, $el) {
return false;
},
onEditorShown: function (field, row, $el, editable) {
return false;
},
});
$.extend($.fn.bootstrapTable.Constructor.EVENTS, {
'editor-init.bs.table': 'onEditorInit',
'editor-save.bs.table': 'onEditorSave',
'editor-shown.bs.table': 'onEditorShown',
});
var BootstrapTable = $.fn.bootstrapTable.Constructor,
_initTable = BootstrapTable.prototype.initTable,
_initBody = BootstrapTable.prototype.initBody;
BootstrapTable.prototype.getEditor = function(key){
return editorCache[key] || textEditor;
}
BootstrapTable.prototype.initTable = function () {
var that = this;
_initTable.apply(this, Array.prototype.slice.apply(arguments));
if (!this.options.editable) {
return;
}
$.each(this.columns, function (i, column) {
if (!column.editable) {
return;
}
that._initColumnEditor(column);
});
this.trigger('editor-init');
};
BootstrapTable.prototype._initColumnEditor = function(column){
var editable = column.editable;
var editorType = editable.type;
var editor = this.getEditor(editorType);
column._editor = editor;
};
BootstrapTable.prototype._setColumnEditorOptions = function(column){
var editable = column.editable;
var editor = column._editor;
if(!editor) {
return;
}
var options = editable.options || {},
attributes = options.attributes,
styles = options.styles;
if(editor._options == options) { //避免重复
return;
}
if(attributes){
Object.keys(attributes).forEach(function(key){
editor.attr(key,attributes[key]);
});
}
if(styles){
Object.keys(styles).forEach(function(key){
editor.css(key,styles[key]);
});
}
if(editable.type == "select" && options.items){
editor.empty();
$.each(options.items, function (index, val) {
let label = val.label || val.value || val;
let value = val.value || val;
var opt = $('<option value="' + value + '">' + label + '</option>');
editor.append(opt);
});
}
editor._options = options;
}
BootstrapTable.prototype._startEdit = function($td){
var that = this;
var $tr = $td.parent(),
item = that.data[$tr.data('index')],
index = $td[0].cellIndex,
fields = that.getVisibleFields(),
field = fields[that.options.detailView && !that.options.cardView ? index - 1 : index],
column = that.columns[that.fieldsColumnsIndex[field]],
value = getItemField(item, field, that.options.escape),
dataIndex = $td.parent().data('index');
var editor = column._editor;
if(!editor){
return;
}
if(editor._row != item || editor._index != index){
that._setColumnEditorOptions(column);
editor._row = item;
editor._index = index;
editor.keydown(function(e) {
if (e.keyCode == 13) {
that._saveEditData($td,editor,padding);
}
});
editor.blur(function(e){
that._saveEditData($td,editor,padding);
});
editor.change(function(e){
that._saveEditData($td,editor,padding);
});
var padding = $td.css("padding");
$td.html("");
$td.css("padding","0px");
$td.append(editor);
editor.focus();
editor.val(value);
that.trigger('editor-shown', column.field, item, $td);
}
}
BootstrapTable.prototype._saveEditData = function($td,editor,padding){
let that = this;
var $tr = $td.parent(),
item = that.data[$tr.data('index')],
index = $td[0].cellIndex,
fields = that.getVisibleFields(),
field = fields[that.options.detailView && !that.options.cardView ? index - 1 : index],
column = that.columns[that.fieldsColumnsIndex[field]],
value = getItemField(item, field, that.options.escape),
dataIndex = $td.parent().data('index');
let tdValue = editor.val();
if(tdValue != value){
this.updateCell({
index: dataIndex,
field: field,
value: tdValue,
reinit:this.options.reInitOnEdit,
});
if(!this.options.reInitOnEdit) {
let args = [tdValue,item,index,field];
let formatText = calculateObjectValue(column,column.formatter,args,tdValue);
$td.html(formatText);
$td.css("padding",padding);
}
that.trigger('editor-save', column.field, item, value, $td);
} else {
let args = [value,item,index,field];
let formatText = calculateObjectValue(column,column.formatter,args,value);
$td.html(formatText);
$td.css("padding",padding);
}
editor._row = undefined;
editor._index = undefined;
};
BootstrapTable.prototype.initBody = function () {
var that = this;
_initBody.apply(this, Array.prototype.slice.apply(arguments));
if (!this.options.editable) {
return;
}
this.$body.find('> tr[data-index] > td').on('click', function (e) {
var $td = $(this);
that._startEdit($td);
});
};
}(jQuery);
使用
- 引包
<script th:src="@{/ruoyi/js/bootstrap-table-editor.js?v=1.1.1}"></script>
- 指定表格的属性中editable为true
let tableOptions = {
columns:columns,
editable:true, //editable需要设置为 true
}
- 在需要编辑的列上面指定editable属性
该属性上面可以指定编辑器的类型,目前支持文本,数字和下拉框。其中editable为true的时候,默认是文本编辑器,指定编辑器类型未select时候,需要指定下拉框的items。
let columns = [{
title: "编号",
field: "id",
sortable: true,
width:200,
editable:false,
},{
title: "月份",
field: "month",
sortable: true,
width:200,
formatter:function(v){
return v + "月"
},
editable:{
type:"select",
options:{
items:[{
value:1,
label:"1月",
},{
value:2,
label:"2月",
},{
value:3,
label:"3月",
},{
value:4,
label:"4月",
},{
value:5,
label:"5月",
}]
}
}
},{
title: "部门",
field: "department",
sortable: true,
width:200,
editable:{
type:"select",
options:{
items:[
"技术部","生产部","管理中心"
]
}
}
},{
title: "管理费用",
field: "fee",
sortable: true,
width:200,
editable:{
type:"number"
}
},{
title: "备注",
field: "comment",
sortable: true,
width:200,
editable:true,
// editable:{
// type:"text"
// }
},];
四、用一个数组保存就地编辑的结果
1、定义一个数组存保存结果
//定义数组,用来存放对象
var objItemList = new Array();
2、触发bootstrap-table-editor中的onEditorSave方法将更改数据添加进数组中
- 在ry.js的bootstraTable中添加onEditorSave回调事件
- 在你写的html文件的options中添加该回调函数
- 编写onEditorSave的具体实现
//编辑保存单元格
function onEditorSave (field, row, oldValue, $el) {
//记录该列的数据类型
var dataType = '';
for (var i = 0; i < fieldList.length; i++) {
if (fieldList[i].field == field) {
dataType = fieldList[i].dataType;
break;
}
}
//检验数据是否符合要求(文本与数字)
var ifDataType = CommonUtils.isNum(dataType, row[field]);
if (ifDataType) {
var objItem = {}; //存储修改的该条数据的信息(行id,模板id,列名|列值)
var ids = new Array(); //存储已经修改过的行id
var fields = new Array(); //存储已经修改过的列名
objItem.id = parseInt(row.id);
objItem.templateId = parseInt(row.templateId);
objItem.data = field + "|" + row[field];
//alert("字段名:" + field + ",当前值:" + row[field] + ",旧值:" + oldValue);
if (objItemList.length > 0) {
//拿到已修改的数据的行号与属性列
for (var i = 0; i < objItemList.length; i++) {
ids.push(objItemList[i].id);
fields.push(objItemList[i].data.split("|")[0]);
}
//判断该数据是否是第一次修改
for (var j = 0; j < ids.length; j++) {
if (ids[j] == row.id && fields[j] == field) {
//说明不是第一次修改,找到该数据删除
for (var k = 0; k < objItemList.length; k++) {
if (objItemList[k].id == row.id) {
objItemList.pop(k);
break;
}
}
}
}
//添加修改的数据
objItemList.push(objItem);
} else {
objItemList.push(objItem);
}
} else {
$.modal.alert("需要" + dataType + "类型的数据,请重新填写符合要求的数据!");
}
}
- 编写保存方法
//就地编辑保存
function inPlaceEditSave() {
var request = {
url: prefix + "/inPlaceEdit",
type: "post",
async: false,
dataType: "json",
data: {
"datas":JSON.stringify(objItemList) //数组转字符串,用于提交到后端
},
success: function (result) {
$.modal.alert(result.content);
//执行完清空objItemList
objItemList = [];
},
error:function() { //ajax提交失败
$.modal.alert("error");
}
};
$.ajax(request);
}
- 后台业务方法的具体实现
/**
* 就地编辑
*
* @param datas 转成字节流的List<ObjItem>
* @return
* */
@Override
public int inPlaceEdit(String datas) {
int num = 0;
//存储ObjItem
List<ObjItem> objItemList = new LinkedList<ObjItem>();
//解析数据
JSONArray dataArr = JSONArray.parseArray(datas);
for (Object data : dataArr) {
ObjItem objItem = new ObjItem();
//模板id
String templateId = data.toString().split(",")[2].split(":")[1].replace("}","");
//数据id
String rowId = data.toString().split(",")[1].split(":")[1];
//查询原数据
ObjItem oldObjItem = objItemService.getObjItem(Integer.valueOf(templateId), Integer.valueOf(rowId));
//得到数据
HashMap<Field, Object> oldData = oldObjItem.getData();
//更改的字段名
String fieldName = data.toString().split(",")[0].replace("{","").split(":")[1].split("\\|")[0].substring(1);
//更改的字段值
String fieldValue = data.toString().split(",")[0].replace("{","").split(":")[1].split("\\|")[1];
//改变的字段
Field changeField = fieldService.getField(Integer.valueOf(templateId), fieldName);
//修改oldData的值
oldData.put(changeField, fieldValue.substring(0, fieldValue.length() - 1));
num += objItemService.updateById(oldObjItem);
}
return num;
}
五、效果与说明
页面效果
- 整个页面就地编辑之前
- 就地编辑之后点击保存
- 点击确认之后数据被修改
说明
1、回调事件的位置
在ry.js中添加回调事件的时候,一定要写在表格的回调事件里,不要写在树的回调事件里,不然会没效果
表格:(加在这个里面)
表格树:(而不是这里)
2、onEditorSave事件
bootstrap-table-editor里的onEditorSave方法是在单元格更改且失焦的时候触发,而x-editable中的onEditableSave方法是在点击提交按钮之后提交。
版权声明:本文为m0_52248951原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。