仅在客户端上使用模式表单向jqGrid添加新行

似乎有很多解决scheme非常接近解决我的问题,但几十个和几十个问题,我倾倒了,似乎并没有一个确切地解决我想要做的事情。 虽然我看到几乎相同的问题没有答案。 我已经尝试了这么多的选项和function组合无济于事。

我想使用模式的forms来添加一个新的行与input的值到jqGrid,但我不希望它提交后发送到服务器。 我希望最终发布到服务器,但只有在客户端用户对从模式表单添加的行执行了额外的编辑(如果需要)之后。 我不希望将任何行保存到远程数据库,直到客户端执行了一些编辑操作,然后dynamic更新其他列。 一旦确认了某个值的状态,就会显示一个保存button,并且网格行可以被发送到服务器。 除非满足这个validation条件,否则不要将行提交给数据库。 我有一些jqGrids在我的应用程序中的其他地方使用,它提交模态窗体的新行数据,但是这个网格我试图完成不同的客户端,它不会立即涉及服务器。 我喜欢模式forms的更直观的界面,用于客户端用户的初始input值,然后编辑内联新行的字段,如果需要的话,这是我的问题是必要的:我可以提交表单作为一个新的行,只有没有任何发布到服务器的动作发生?

我在jqGrid Wiki资源中看到一个用户发表的评论,他说如果“clientArray”是为了使用Grids模式表单提交选项“editurl:”clientArray“而input的值,模式表单不会吐出”没有URL “消息,但它仍然没有和一个新的行不添加到网格。我已经把网格数据types作为本地”数据types:“clientSide”“,但得到相同的”没有URL被设置“的错误信息。对于由自定义button调用的模式forms非常简单,如下所示:

(“footerrow,userDataOnFooter和altRows”选项被包括在摘要页脚中的值更新的一部分,该页脚与通过模式forms添加的新行的单元格执行的编辑相关)

jQuery("#grid_test").jqGrid({ url:'/grid_test_url.asp?id=' + vId, datatype: "clientSide", colNames: ['ID','Col 1', 'Col 2', 'Col 3','Col 4'], colModel: [ {name:'id',index:'id',width:90,align:"center",editable:true,editoptions:{size:25}, formoptions: {...}, editrules: {...}}, {name:'col1',index:'col1',width:130,align:"right",editable:true,editoptions:{size:25}, formoptions: {}, editrules: {}}, {name:'col2',index:'col2',width:130,align:"right",editable:true,editoptions:{size: 25}, formoptions: {}, editrules: {}}, {name:'col3',index:'col3',width:130,align:"right",editable: true,editoptions:{size:25}, formoptions: {}, editrules: {}}, {name:'col4',index:'col4',width:130,align:"right",editable:true,editoptions:{ size: 25 }, formoptions: {}, editrules: {}} ], rowNum:5, rowList:[5,10,20], pager: '#pgrid_test', toolbar: [true, "top"], editurl: '', //not sure what would go here to block attempted post by the Submit action of the modal form width: 500, sortname: 'id', viewrecords: true, sortorder: "asc", multiselect: true, cellEdit: true, caption: "Grid Test Add New Row", footerrow: true, userDataOnFooter: true, altRows: true }) jQuery("#grid_test").jqGrid('navGrid', '#pgrid_test', { add: false, edit: false, del: false }) //append custom button $("#t_grid_test").append("<input type='button' class='add' value='Add New Row' style='height:20px; color:green; font-size:11px;' />"); $("input.add", "#t_grid_test").click(function () { jQuery("#grid_test").jqGrid('editGridRow', "new", { jqModal: true, savekey: [true, 13], navkeys: [true, 38, 40], bottominfo: "Fields marked with (*) are required. ", addCaption: 'New Row Values', width: 300, dataheight: 200, recreateForm: true, //checkOnUpdate: true, //checkOnSubmit: true, //reloadAfterSubmit: true, closeOnEscape: true, closeAfterAdd: true //clearAfterAdd: true }) }); 

我希望这是相当清楚的。 看起来应该是相当简单的添加一行使用模式forms没有立即张贴到服务器,但我不能解决scheme。 如果我没有及时点击图标以获得正确的答案,请耐心等待,但是当我知道要点击什么时,请相应通知。 :) 提前谢谢了。 杰瑞

表单编辑的当前版本不支持本地数据types。 尽pipe如此,如果使用一些更长的代码,也可以实现。 我前段时间创build了这个demo,并在这里发布了在jqGrid中实现本地编辑支持的build议。 到现在为止还没有实现,但是你可以用我的例子来实现你所需要的。

我包含下面的代码:

 var lastSel, mydata = [ {id:"1", invdate:"2007-10-01",name:"test", note:"note", amount:"200.00",tax:"10.00",closed:true, ship_via:"TN",total:"210.00"}, {id:"2", invdate:"2007-10-02",name:"test2", note:"note2", amount:"300.00",tax:"20.00",closed:false,ship_via:"FE",total:"320.00"}, {id:"3", invdate:"2007-09-01",name:"test3", note:"note3", amount:"400.00",tax:"30.00",closed:false,ship_via:"FE",total:"430.00"}, {id:"4", invdate:"2007-10-04",name:"test4", note:"note4", amount:"200.00",tax:"10.00",closed:true ,ship_via:"TN",total:"210.00"}, {id:"5", invdate:"2007-10-31",name:"test5", note:"note5", amount:"300.00",tax:"20.00",closed:false,ship_via:"FE",total:"320.00"}, {id:"6", invdate:"2007-09-06",name:"test6", note:"note6", amount:"400.00",tax:"30.00",closed:false,ship_via:"FE",total:"430.00"}, {id:"7", invdate:"2007-10-04",name:"test7", note:"note7", amount:"200.00",tax:"10.00",closed:true ,ship_via:"TN",total:"210.00"}, {id:"8", invdate:"2007-10-03",name:"test8", note:"note8", amount:"300.00",tax:"20.00",closed:false,ship_via:"FE",total:"320.00"}, {id:"9", invdate:"2007-09-01",name:"test9", note:"note9", amount:"400.00",tax:"30.00",closed:false,ship_via:"TN",total:"430.00"}, {id:"10",invdate:"2007-09-08",name:"test10",note:"note10",amount:"500.00",tax:"30.00",closed:true ,ship_via:"TN",total:"530.00"}, {id:"11",invdate:"2007-09-08",name:"test11",note:"note11",amount:"500.00",tax:"30.00",closed:false,ship_via:"FE",total:"530.00"}, {id:"12",invdate:"2007-09-10",name:"test12",note:"note12",amount:"500.00",tax:"30.00",closed:false,ship_via:"FE",total:"530.00"} ], grid = $("#list"), onclickSubmitLocal = function(options,postdata) { var grid_p = grid[0].p, idname = grid_p.prmNames.id, grid_id = grid[0].id, id_in_postdata = grid_id+"_id", rowid = postdata[id_in_postdata], addMode = rowid === "_empty", oldValueOfSortColumn; // postdata has row id property with another name. we fix it: if (addMode) { // generate new id var new_id = grid_p.records + 1; while ($("#"+new_id).length !== 0) { new_id++; } postdata[idname] = String(new_id); } else if (typeof(postdata[idname]) === "undefined") { // set id property only if the property not exist postdata[idname] = rowid; } delete postdata[id_in_postdata]; // prepare postdata for tree grid if(grid_p.treeGrid === true) { if(addMode) { var tr_par_id = grid_p.treeGridModel === 'adjacency' ? grid_p.treeReader.parent_id_field : 'parent_id'; postdata[tr_par_id] = grid_p.selrow; } $.each(grid_p.treeReader, function (i){ if(postdata.hasOwnProperty(this)) { delete postdata[this]; } }); } // decode data if there encoded with autoencode if(grid_p.autoencode) { $.each(postdata,function(n,v){ postdata[n] = $.jgrid.htmlDecode(v); // TODO: some columns could be skipped }); } // save old value from the sorted column oldValueOfSortColumn = grid_p.sortname === "" ? undefined: grid.jqGrid('getCell',rowid,grid_p.sortname); // save the data in the grid if (grid_p.treeGrid === true) { if (addMode) { grid.jqGrid("addChildNode",rowid,grid_p.selrow,postdata); } else { grid.jqGrid("setTreeRow",rowid,postdata); } } else { if (addMode) { grid.jqGrid("addRowData",rowid,postdata,options.addedrow); } else { grid.jqGrid("setRowData",rowid,postdata); } } if ((addMode && options.closeAfterAdd) || (!addMode && options.closeAfterEdit)) { // close the edit/add dialog $.jgrid.hideModal("#editmod"+grid_id, {gb:"#gbox_"+grid_id,jqm:options.jqModal,onClose:options.onClose}); } if (postdata[grid_p.sortname] !== oldValueOfSortColumn) { // if the data are changed in the column by which are currently sorted // we need resort the grid setTimeout(function() { grid.trigger("reloadGrid", [{current:true}]); },100); } // !!! the most important step: skip ajax request to the server this.processing = true; return {}; }, editSettings = { //recreateForm:true, jqModal:false, reloadAfterSubmit:false, closeOnEscape:true, savekey: [true,13], closeAfterEdit:true, onclickSubmit:onclickSubmitLocal }, addSettings = { //recreateForm:true, jqModal:false, reloadAfterSubmit:false, savekey: [true,13], closeOnEscape:true, closeAfterAdd:true, onclickSubmit:onclickSubmitLocal }, delSettings = { // because I use "local" data I don't want to send the changes to the server // so I use "processing:true" setting and delete the row manually in onclickSubmit onclickSubmit: function(options) { //, rowid) { var grid_id = grid[0].id, grid_p = grid[0].p, newPage = grid_p.page, rowids = grid_p.multiselect? grid_p.selarrrow: [grid_p.selrow]; // reset the value of processing option to true // because the value can be changed by jqGrid options.processing = true; // delete selected row/rows (multiselect:true) $.each(rowids, function () { grid.delRowData(this); }); // delete the row //grid.delRowData(rowid); $.jgrid.hideModal("#delmod"+grid_id, {gb:"#gbox_"+grid_id,jqm:options.jqModal,onClose:options.onClose}); if (grid_p.lastpage > 1) {// on the multipage grid reload the grid if (grid_p.reccount === 0 && newPage === grid_p.lastpage) { // if after deliting there are no rows on the current page // which is the last page of the grid newPage--; // go to the previous page } // reload grid to make the row from the next page visable. grid.trigger("reloadGrid", [{page:newPage}]); } return true; }, processing:true }, initDateEdit = function(elem) { setTimeout(function() { $(elem).datepicker({ dateFormat: 'dd-M-yy', autoSize: true, showOn: 'button', // it dosn't work in searching dialog changeYear: true, changeMonth: true, showButtonPanel: true, showWeek: true }); //$(elem).focus(); },100); }, initDateSearch = function(elem) { setTimeout(function() { $(elem).datepicker({ dateFormat: 'dd-M-yy', autoSize: true, //showOn: 'button', // it dosn't work in searching dialog changeYear: true, changeMonth: true, showButtonPanel: true, showWeek: true }); //$(elem).focus(); },100); }; grid.jqGrid({ datatype:'local', data: mydata, colNames:['Inv No','Date','Client','Amount','Tax','Total','Closed','Shipped via','Notes'], colModel:[ {name:'id',index:'id',width:70,align:'center',sorttype: 'int',searchoptions:{sopt:['eq','ne']}}, {name:'invdate',index:'invdate',width:80, align:'center', sorttype:'date', formatter:'date', formatoptions: {newformat:'dM-Y'}, editable:true, datefmt: 'dM-Y', editoptions: {dataInit:initDateEdit}, searchoptions: {dataInit:initDateSearch}}, {name:'name',index:'name',editable: true, width:70, editrules:{required:true}}, {name:'amount',index:'amount',width:100, formatter:'number', editable: true, align:'right'}, {name:'tax',index:'tax',width:70, formatter:'number', editable: true, align:'right'}, {name:'total',index:'total',width:120, formatter:'number', editable: true, align:'right'}, {name:'closed',index:'closed',width:110,align:'center',editable: true, formatter: 'checkbox', edittype:'checkbox',editoptions:{value:'Yes:No',defaultValue:'Yes'}, stype: 'select', searchoptions: { sopt:['eq','ne'], value:':All;true:Yes;false:No' }}, {name:'ship_via',index:'ship_via',width:120,align:'center',editable: true, formatter:'select', edittype:'select',editoptions:{value:'FE:FedEx;TN:TNT;IN:Intim', defaultValue:'Intime'}, stype:'select', searchoptions:{value:':All;FE:FedEx;TN:TNT;IN:Intim'}}, {name:'note',index:'note',width:100,sortable:false,editable:true,edittype:'textarea'} ], rowNum:10, rowList:[5,10,20], pager: '#pager', gridview:true, rownumbers:true, autoencode:true, ignoreCase:true, sortname: 'invdate', viewrecords: true, sortorder: 'desc', caption:'How to implement local form editing', height: '100%', editurl: 'clientArray', ondblClickRow: function(rowid, ri, ci) { var p = grid[0].p; if (p.selrow !== rowid) { // prevent the row from be unselected on double-click // the implementation is for "multiselect:false" which we use, // but one can easy modify the code for "multiselect:true" grid.jqGrid('setSelection', rowid); } grid.jqGrid('editGridRow', rowid, editSettings); }, onSelectRow: function(id) { if (id && id !== lastSel) { // cancel editing of the previous selected row if it was in editing state. // jqGrid hold intern savedRow array inside of jqGrid object, // so it is safe to call restoreRow method with any id parameter // if jqGrid not in editing state if (typeof lastSel !== "undefined") { grid.jqGrid('restoreRow',lastSel); } lastSel = id; } } }).jqGrid('navGrid','#pager',{},editSettings,addSettings,delSettings, {multipleSearch:true,overlay:false, onClose:function(form){ // if we close the search dialog during the datapicker are opened // the datepicker will stay opened. To fix this we have to hide // the div used by datepicker $("div#ui-datepicker-div.ui-datepicker").hide(); }}); 

更新 :代码更改与jqGrid 4.4.1我张贴在答案 。

更新2 : 答案提供了4.5.4的更新。

更新3 :新的4.7版本的jqGrid支持现在编辑本地数据。 这里使用新版本的相应演示。 我只需要添加新reformatAfterEdit: true选项formatter: "date" 。 另一个演示使用jqGrid 4.6。

编辑为4.3.2网格的行为有所改变

4.3.1

 onclickSubmitLocal = function(options,postdata) { .... // !!! the most important step: skip ajax request to the server this.processing = true; return {}; 

4.3.2

 onclickSubmitLocal = function(options,postdata) { .... // !!! the most important step: skip ajax request to the server options.processing = true; return {}; 

否则网格返回的URL错误