也来说说jQuery的grid插件Flexigrid的几点主要改进
也来说说jQuery的grid插件Flexigrid的几点重要改进
之所以选择Flexigrid作为我们的grid,三个重要原因:
1.我们选择了jQuery作为基础js lib;
2.要能全面控盘,也就是说只要需要,可以在没有很强的js牛人参与的情况下,能自行扩充;
3.性能和browser兼容性要好
Ok,下面来谈谈我的几点关键改进(这里忽略参考来的,仅谈自己的扩展和改进,并且仅探讨几个关键改进,细小的就不谈了)
1.兼容复杂的JSON格式。
我们都知道,不可能所有的POJO都是完全扁平的,比如Booking类,里面的定义可能是这样的:
出来的JSON就可能是这样的:
注意这里的user和hotel都是一个子对象。
在这种情况下,Flexigrid并不能支持,原来的代码是这样的:
大家可以看到,如果我们的colModel配置如下:
这是无法得到正确的答案的,因为selectedName是hotel.name比如,但data.rows[i][selectedName]这种写法永远都是取不到hotel.name的值的,所以总是为null.
而且大家注意到,上面的js的效率非常差,两个嵌套循环简直是浪费。
改进其实很简单,代码也更少更精练,而且由于免去了多余的循环,性能得到大幅的提升。
代码如下:
需要再提一下的是:我这里的render方法由于在第二个参数中加了current row的对象,所以非常方便我们在字段中引用其他属性值,这也是使得flexigrid变得更加可用的一点小改进。比如:
2.加入小计功能。需要说明的是,这里的统计仅对当前页进行简单的客户端的统计——如果要做更复杂的,建议在后端做,然后当一个普通的record来渲染。
首先加入一个插件范围的全局函数:
然后在addData中加入,加在$(t).append(tbody)后面,也就是说,先同原来的逻辑一样渲染整个grid,再加入特定的summary行。
我这里支持合计sum,平均average,如果不能满足需求,也可以自定义。
格式如下:sum|average:scale。可以自定义精度。
使用举例:
自定义的小计函数如下:
3.加载过程的提示消息处理。这一点原来有点搞,一旦你不启用翻页,连加载提示消息都没了,这个有点过分——未必所有的list都需要翻页的吧。
这里涉及几个小地方的调整,我就懒得贴代码了,这里提一下即可,有兴趣的自己看。
最后附上我在用的最新代码,对了,我废掉了xml格式的支持,JSON就挺好了,性能好还省带宽。
参考:
jQuery插件flexigrid使用总结: http://www.iteye.com/topic/611837
这一点我做过更新,这样可以保证传递给自定义render函数的参数为:
这个小小的改进却极大的方便了获取本行其他任何元素的可能,请参考。
没什么大问题啊,前面的行号也对的啊(除了css不是特别妥当之外)
你可能想问后面的undefined问题,那应该是其他问题,我建议你用FF调试一下
最好把行的定义也贴出来,可以看的更明显
1. 如果是在当前页面跳转,回来肯定刷新了,对吧
如果这样,那条记录可能都已经被过滤掉了或者干脆干掉了,怎么“看到原来的”?
如果你认为还是会列出来的,那好,回传那个页面数和记录ID,用js处理下(高亮什么的)即可
2. 如果是新开页面,这之间几乎没有任何关系,打开新页面的时候用js处理下当前记录即可
你说呢?
我也不认为这个插件是最好的,但却是可以控制的,这就是你接下来定制开发的基础。
你完全可以自己去扩展开发,以满足特定的需求——如果你实现了,别忘了分享:)
没什么大问题啊,前面的行号也对的啊(除了css不是特别妥当之外)
你可能想问后面的undefined问题,那应该是其他问题,我建议你用FF调试一下
最好把行的定义也贴出来,可以看的更明显
出现是undefine 是数据库为空值的时候读出来就这样,在sql上转码就好了。
之所以选择Flexigrid作为我们的grid,三个重要原因:
1.我们选择了jQuery作为基础js lib;
2.要能全面控盘,也就是说只要需要,可以在没有很强的js牛人参与的情况下,能自行扩充;
3.性能和browser兼容性要好
Ok,下面来谈谈我的几点关键改进(这里忽略参考来的,仅谈自己的扩展和改进,并且仅探讨几个关键改进,细小的就不谈了)
1.兼容复杂的JSON格式。
我们都知道,不可能所有的POJO都是完全扁平的,比如Booking类,里面的定义可能是这样的:
public class Booking implements Serializable { private Long id; private User user; private Hotel hotel; @DateTimeFormat(pattern = "MM-dd-yyyy") private Date checkinDate; @DateTimeFormat(pattern = "MM-dd-yyyy") private Date checkoutDate; private String creditCard; private String creditCardName; private int creditCardExpiryMonth; private int creditCardExpiryYear; private boolean smoking; private int beds; ... }
出来的JSON就可能是这样的:
{"total":1,"page":1,"rows":[{"id":34,"total":300,"description":"70 Park Avenue Hotel, Feb 10, 2011 to Feb 11, 2011","user":{"name":"Keith","password":null,"username":"keith"},"checkinDate":1297267200000,"checkoutDate":1297353600000,"nights":1,"hotel":{"address":"70 Park Avenue","name":"70 Park Avenue Hotel","id":9,"state":"NY","country":"USA","price":300,"city":"NY","zip":"10011"},"creditCard":null,"smoking":false,"beds":0,"creditCardName":null,"creditCardExpiryMonth":0,"creditCardExpiryYear":0,"amenities":null}]}
注意这里的user和hotel都是一个子对象。
在这种情况下,Flexigrid并不能支持,原来的代码是这样的:
for (j = 0; j < p.colModel.length; j++) { var cm = p.colModel[j]; var selectedName = cm.name; // properties set but not in data, reset to '' if (data.rows[i][selectedName] == null) { data.rows[i][selectedName] = ''; } // push the current row data to array tdVal $.each(data.rows[i], function(name, value) { if (selectedName == name) { if (cm.render) { val = cm.render(value); } else { val = value; } tdVal.push(val); } }); }
大家可以看到,如果我们的colModel配置如下:
colModel : [ {display: 'id', name : 'id', width : 10, align: 'left'}, {display: 'Hotel Name', name : 'hotel.name', width : 150, sortable : true, align: 'left'}, {display: 'Hotel Address', name : 'hotel.address', width : 200, sortable : true, align: 'center'}, {display: 'Hotel City', name : 'hotel.city', width : 80, align: 'left'}, {display: 'Hotel State', name : 'hotel.state', width : 80, align: 'left'}, {display: 'Check in Date', name : 'checkinDate', width : 100, align: 'left'}, {display: 'Check out Date', name : 'checkoutDate', width : 100, align: 'right'},//sum {display: 'Action', name : 'cancel', width : 50, align: 'center', render: renderCancelIt}//using custom render ]
这是无法得到正确的答案的,因为selectedName是hotel.name比如,但data.rows[i][selectedName]这种写法永远都是取不到hotel.name的值的,所以总是为null.
而且大家注意到,上面的js的效率非常差,两个嵌套循环简直是浪费。
改进其实很简单,代码也更少更精练,而且由于免去了多余的循环,性能得到大幅的提升。
代码如下:
for (j=0;j<p.colModel.length;j++){ var cm = p.colModel[j]; if(cm.summary) isSummary = true; //10/02/2011 enhanced by bright for support complex properties by rewrite this part //using eval for getting the value no matter how complex it is val = eval("data.rows[" + i +"]." + cm.name); if (val==null) val = ""; if (cm.render) { //07/02/2011 by bright: let custom render more powerful //val = cm.render(value); val = cm.render(val, row); } tdVal.push(val); } }
需要再提一下的是:我这里的render方法由于在第二个参数中加了current row的对象,所以非常方便我们在字段中引用其他属性值,这也是使得flexigrid变得更加可用的一点小改进。比如:
function getMoreInfo(content, currentRow){ var str = "id=" + currentRow.id + ";name=" + currentRow.name; return '<input type="button" name="doit" value="More Info" onclick="alert(\'' + str + '\')">'; }
2.加入小计功能。需要说明的是,这里的统计仅对当前页进行简单的客户端的统计——如果要做更复杂的,建议在后端做,然后当一个普通的record来渲染。
首先加入一个插件范围的全局函数:
appendSummaryFooter: function(tbody){ var data = []; for (j=0;j<p.colModel.length;j++){ var cm = p.colModel[j]; var summary = cm.summary; if(summary){ var vals = []; var trs = $(".flexigrid .bDiv table tbody tr"); if(trs.length > 0){ for(var x=0; x<trs.length; x++){ var v = $("td:eq("+j+")",trs[x]).text(); vals.push(v); } } var resultValue = 0.00; var fixed = 0; if(typeof(summary)=="function"){ resultValue = summary(vals); }else if(summary.indexOf("average")==0){ var parts = summary.split(":"); fixed = (parts[1] != null) ? parts[1] : 0; var cnt = 0; $(vals).each(function(i,value){ cnt++; resultValue += parseFloat(value); }); resultValue = resultValue / cnt; resultValue = resultValue.toFixed(fixed); }else if(summary.indexOf("sum")==0){ var parts = summary.split(":"); fixed = (parts[1] != null) ? parts[1] : 0; $(vals).each(function(i,value){ resultValue += parseFloat(value); }); resultValue = resultValue.toFixed(fixed); } //push to the reslut array data.push(resultValue); }else{ data.push(""); } } if(data){ var footer = $('<tr id="trSummary" style="background:gray"></tr>'); $(data).each(function(i,v){ var div = $('<div style="text-align: right;">' + v + '</div>'); $(footer).append($('<td align="right"></td>').append(div)); }); $(tbody).append(footer); } }
然后在addData中加入,加在$(t).append(tbody)后面,也就是说,先同原来的逻辑一样渲染整个grid,再加入特定的summary行。
$(t).append(tbody); //06012011 add by Bright Zheng if(isSummary){ this.appendSummaryFooter(tbody); }
我这里支持合计sum,平均average,如果不能满足需求,也可以自定义。
格式如下:sum|average:scale。可以自定义精度。
使用举例:
{display: 'Price_a', name : 'price', width : 60, align: 'right',summary: 'average:2'},//sum {display: 'Price_s', name : 'price', width : 60, align: 'right',summary: 'sum:0'},//average {display: 'Price_c', name : 'price', width : 60, align: 'right',summary: customSum},//custom
自定义的小计函数如下:
//custom summary function function customSum(arrayOfValue){ var resultValue = 0.00; $(arrayOfValue).each(function(i,value){ resultValue += parseFloat(value); }); return resultValue.toFixed(3); }
3.加载过程的提示消息处理。这一点原来有点搞,一旦你不启用翻页,连加载提示消息都没了,这个有点过分——未必所有的list都需要翻页的吧。
这里涉及几个小地方的调整,我就懒得贴代码了,这里提一下即可,有兴趣的自己看。
最后附上我在用的最新代码,对了,我废掉了xml格式的支持,JSON就挺好了,性能好还省带宽。
参考:
jQuery插件flexigrid使用总结: http://www.iteye.com/topic/611837
1 楼
arong
2011-03-23
刚要研究flexigrid,学习一下。
2 楼
arong
2011-04-04
如何根据本行其它某个单元格的值作判断,格式化行背景?
3 楼
itstarting
2011-04-05
arong 写道
如何根据本行其它某个单元格的值作判断,格式化行背景?
这一点我做过更新,这样可以保证传递给自定义render函数的参数为:
if (cm.render) { //07/02/2011 by bright: let custom render more powerful //val = cm.render(value); val = cm.render(val, row); }
这个小小的改进却极大的方便了获取本行其他任何元素的可能,请参考。
4 楼
wzl1219
2011-09-01
楼主你好,其实有个问题,我想问很久了。我最近也在改这个插件,我在表中加了很多<input>的对象,想通过这个表去提交,做一些类似更新数据库的功能,但是不知道,像这种flexigrid做出来的表,我如果直接放在form中提交,得到的会是什么?lz觉得这个插件能用于表单提交吗?
5 楼
renlei413326889
2011-09-24
楼主,我想加一个显示行号的功能,在addData方法中$.each(data.rows, function(i, row) { ...循环之前添加var pageStartNum = ( p.page - 1 ) * p.rp; (记录当前页的第一行行号),然后在循环里面添加
if (p.showRowNum){ var currentNum = pageStartNum + i + 1; var td = $("<td align=\"center\">" + currentNum + "</td>"); $(td).attr("width","30") .attr("id","gridRowNum") .css({ "font-weight" : "bold" }); $(tr).append(td); }这段代码,并且在
// create model if any if (p.colModel) {中添加
if (p.showRowNum){ var th = document.createElement('th'); $(th).attr('width', '50').attr('align', 'center'). attr('id', 'gridRowNumColumn'); $(th).text('行号'); $(tr).append(th).attr('axis', 'colRowNum');; }不知道最后显示的时候为什么出现下面截图的样子了,js技术很菜,照着网上的改的,出不来http://dl.iteye.com/upload/attachment/559631/ba64ed08-d142-34a7-93a2-9120639b0db0.png
6 楼
itstarting
2011-09-25
renlei413326889 写道
楼主,我想加一个显示行号的功能,在addData方法中$.each(data.rows, function(i, row) { ...循环之前添加var pageStartNum = ( p.page - 1 ) * p.rp; (记录当前页的第一行行号),然后在循环里面添加
if (p.showRowNum){ var currentNum = pageStartNum + i + 1; var td = $("<td align=\"center\">" + currentNum + "</td>"); $(td).attr("width","30") .attr("id","gridRowNum") .css({ "font-weight" : "bold" }); $(tr).append(td); }这段代码,并且在
// create model if any if (p.colModel) {中添加
if (p.showRowNum){ var th = document.createElement('th'); $(th).attr('width', '50').attr('align', 'center'). attr('id', 'gridRowNumColumn'); $(th).text('行号'); $(tr).append(th).attr('axis', 'colRowNum');; }不知道最后显示的时候为什么出现下面截图的样子了,js技术很菜,照着网上的改的,出不来http://dl.iteye.com/upload/attachment/559631/ba64ed08-d142-34a7-93a2-9120639b0db0.png
没什么大问题啊,前面的行号也对的啊(除了css不是特别妥当之外)
你可能想问后面的undefined问题,那应该是其他问题,我建议你用FF调试一下
最好把行的定义也贴出来,可以看的更明显
7 楼
tgn2kino
2011-09-30
请教个问题。
在Flexigrid中选中一条记录后跳转到其他页面进行操作,之后再回到Flexigrid页面时,想要能看到原来Flexigrid中的数据,该如何实现?
在Flexigrid中选中一条记录后跳转到其他页面进行操作,之后再回到Flexigrid页面时,想要能看到原来Flexigrid中的数据,该如何实现?
8 楼
itstarting
2011-10-03
tgn2kino 写道
请教个问题。
在Flexigrid中选中一条记录后跳转到其他页面进行操作,之后再回到Flexigrid页面时,想要能看到原来Flexigrid中的数据,该如何实现?
在Flexigrid中选中一条记录后跳转到其他页面进行操作,之后再回到Flexigrid页面时,想要能看到原来Flexigrid中的数据,该如何实现?
1. 如果是在当前页面跳转,回来肯定刷新了,对吧
如果这样,那条记录可能都已经被过滤掉了或者干脆干掉了,怎么“看到原来的”?
如果你认为还是会列出来的,那好,回传那个页面数和记录ID,用js处理下(高亮什么的)即可
2. 如果是新开页面,这之间几乎没有任何关系,打开新页面的时候用js处理下当前记录即可
你说呢?
9 楼
tcrct
2011-10-04
博主,请问能实现多列表头吗?如能加入多列表头,及分组显示等,基本上就满足了大部分的开发显示列表了.
10 楼
itstarting
2011-10-04
tcrct 写道
博主,请问能实现多列表头吗?如能加入多列表头,及分组显示等,基本上就满足了大部分的开发显示列表了.
我也不认为这个插件是最好的,但却是可以控制的,这就是你接下来定制开发的基础。
你完全可以自己去扩展开发,以满足特定的需求——如果你实现了,别忘了分享:)
11 楼
hanxi545
2011-11-03
itstarting 写道
renlei413326889 写道
楼主,我想加一个显示行号的功能,在addData方法中$.each(data.rows, function(i, row) { ...循环之前添加var pageStartNum = ( p.page - 1 ) * p.rp; (记录当前页的第一行行号),然后在循环里面添加
if (p.showRowNum){ var currentNum = pageStartNum + i + 1; var td = $("<td align=\"center\">" + currentNum + "</td>"); $(td).attr("width","30") .attr("id","gridRowNum") .css({ "font-weight" : "bold" }); $(tr).append(td); }这段代码,并且在
// create model if any if (p.colModel) {中添加
if (p.showRowNum){ var th = document.createElement('th'); $(th).attr('width', '50').attr('align', 'center'). attr('id', 'gridRowNumColumn'); $(th).text('行号'); $(tr).append(th).attr('axis', 'colRowNum');; }不知道最后显示的时候为什么出现下面截图的样子了,js技术很菜,照着网上的改的,出不来http://dl.iteye.com/upload/attachment/559631/ba64ed08-d142-34a7-93a2-9120639b0db0.png
没什么大问题啊,前面的行号也对的啊(除了css不是特别妥当之外)
你可能想问后面的undefined问题,那应该是其他问题,我建议你用FF调试一下
最好把行的定义也贴出来,可以看的更明显
出现是undefine 是数据库为空值的时候读出来就这样,在sql上转码就好了。