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

时间:2011-04-10 10:08:34

标签: jqgrid local editing form-editing

似乎有许多解决方案非常接近于解决我的问题,但是我所倾倒的几十个问题似乎并没有完全解决我正在尝试做的事情。虽然我看到几乎同样的问题没有答案。我尝试了很多选项和功能的组合无济于事。

我想使用模态表单将带有输入值的新行添加到jqGrid,但我不希望它在提交时发布到服务器。我想最终发布到服务器,但只有在客户端用户对从模式表单添加的行执行了额外编辑(如果需要)之后。我不希望任何行保存到远程数据库,直到客户端执行了一些编辑,这些编辑又动态更新其他列。验证某个值的某个状态后,将显示“保存”按钮,并且可以将“网格”行发布到服务器。除非满足此验证条件,否则不会将行提交给数据库。我在我的应用程序的其他地方使用了一些jqGrids,它们发布了提交的模式表单的新行数据,但是这个网格我试图完成与客户端不同的东西,而不是立即涉及服务器。我喜欢使用客户端用户初始输入值的模态表单的更直观的界面,然后根据需要编辑内联新行的字段,这是我的问题所必需的:我可以将表单作为新行提交发生在服务器上的任何发布操作?

我在jqGrid Wiki资源中看到一个用户发表的评论,该用户说“clientArray”是输入的值,使用网格模式表单提交选项“editurl:”clientArray“模式表单不会吐出”否URL设置为“消息,但它仍然存在并且新行未添加到网格中。我已将Grid数据类型设置为本地”数据类型:'clientSide'“但是获得相同的”未设置URL“错误消息。对于由自定义按钮调用的模式形式,脚本非常简单,如下所示:

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

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
    })
});

我希望这是相当清楚的。看起来应该相当简单,使用模态形式添加一行而不立即发布到服务器,但我无法解决问题。如果我没有及时点击图标以获得适当的信用答案,请耐心等待,但是当我知道点击什么时我会这样,所以请相应地提出建议。 :) 提前谢谢了。 杰里

2 个答案:

答案 0 :(得分:14)

表单编辑的当前版本不支持本地数据类型。然而,如果使用更长的代码,可以实现。我前段时间创建了the demo并发布了here建议来实现jqGrid中的本地编辑支持。到目前为止它还没有实现,但你可以用我的例子来实现你需要的东西。

我包含以下代码:

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:'d-M-Y'}, editable:true, datefmt: 'd-M-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我发布在the answer

更新2 The answer提供4.5.4的更新。

更新3 :jqGrid的新4.7版本现在支持表单编辑本地数据。使用新版本的相应演示是here。我只需添加reformatAfterEdit: true的新formatter: "date"选项即可。 Another demo使用jqGrid 4.6。

答案 1 :(得分:1)

EDIT 作为4.3.2,Grid的行为发生了变化

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 {};

否则网格返回网址错误