jqGrid 在编辑时访问单元格数据

2022-01-19 00:00:00 jquery javascript jqgrid

我目前正在使用 afterSaveCell 来处理手动更新网格中的某些单元格.如果用户使用 enter 保存当前正在编辑的单元格,我可以正常工作.

I'm currently using afterSaveCell to handle manually updating some cells in a grid. I have this working fine if the user uses enter to save the currently editing cell.

不幸的是,如果他们单击或跳出单元格,他们正在直接编辑到另一个单元格,我无法再获取新编辑单元格的单元格值,因为 getCell 只会返回 html输入控制.

Unfortunately, if they click or tab out of the cell they are editing directly into another cell I can no longer grab the cell value of the newly edited cell as getCell will only return the html for the input control.

总之,有没有什么方法可以访问单元格的值,即使它正在被编辑?

In summary, is there any way to access the value of the cell even while it is being edited?

jQuery(document).ready(function () {
    var mydata = [
        {id:"1", invdate:"2007-10-01",name:"test",  note:"note",  amount:"200.00",tax:"10.00",total:"210.00"},
        {id:"2", invdate:"2007-10-02",name:"test2", note:"note2", amount:"300.00",tax:"20.00",total:"320.00"},
        {id:"3", invdate:"2007-09-01",name:"test3", note:"note3", amount:"400.00",tax:"30.00",total:"430.00"},
        {id:"4", invdate:"2007-10-04",name:"test",  note:"note4", amount:"200.00",tax:"10.00",total:"210.00"},
        {id:"5", invdate:"2007-10-05",name:"test5", note:"note5", amount:"300.00",tax:"20.00",total:"320.00"},
        {id:"6", invdate:"2007-09-06",name:"test",  note:"note6", amount:"400.00",tax:"30.00",total:"430.00"},
        {id:"7", invdate:"2007-10-04",name:"test7", note:"note7", amount:"200.00",tax:"10.00",total:"210.00"},
        {id:"8", invdate:"2007-10-03",name:"test8", note:"note8", amount:"300.00",tax:"20.00",total:"320.00"},
        {id:"9", invdate:"2007-09-01",name:"test",  note:"note9", amount:"400.00",tax:"30.00",total:"430.00"},
        {id:"10",invdate:"2007-09-08",name:"test10",note:"note10",amount:"500.00",tax:"30.00",total:"530.00"},
        {id:"11",invdate:"2007-09-08",name:"test11",note:"note11",amount:"500.00",tax:"30.00",total:"530.00"},
        {id:"12",invdate:"",name:"TOTAL",  note:"",amount:"",tax:"",total:""}
    ];

    var grid = $("#list");

    grid.jqGrid({
        cellsubmit: 'remote',
        cellurl: '/Example/GridSave',
        datatype: "local",
        data: mydata,
        mtype: 'POST',
        colNames: ['Inv No', 'Date', 'Client', 'Amount', 'Tax', 'Total', 'Notes'],
        colModel: [
            { name: 'id', index: 'id', width: 65, sorttype: 'int', hidden: true },
            { name: 'invdate', index: 'invdate', width: 120, align: 'center', formatter: 'date', formatoptions: { newformat: 'd-M-Y' }, sortable: false },
            { name: 'name', index: 'name', editable: true, width: 90, sortable: false },
            { name: 'amount', index: 'amount', editable: true, width: 70, formatter: 'number', align: 'right', sortable: false },
            { name: 'tax', index: 'tax', editable: true, width: 60, formatter: 'number', align: 'right', sortable: false },
            { name: 'total', index: 'total', editable: true, width: 60, formatter: 'number', align: 'right', sortable: false },
            { name: 'note', index: 'note', width: 100, sortable: false }
        ],
        rowNum: 1000,
        pager: '#pager',
        viewrecords: true,
        sortorder: "desc",
        caption: "afterSaveCell Issue",
        height: "100%",
        cellEdit: true,
        gridComplete: function () {
            calculateTotal();
        },
        afterSaveCell: function (rowid, name, val, iRow, iCol) {
            calculateTotal();
        }
    });
});

function calculateTotal() {
    var totalAmount = 0;
    var totalTax = 0;

    var grid = jQuery("#list");

    var ids = grid.jqGrid('getDataIDs');
    for (var i = 0; i < ids.length; i++) {
        var id = ids[i];

        if (grid.jqGrid('getCell', id, 'name') === "TOTAL") {
            grid.jqGrid('setRowData', id, {
                'amount': totalAmount,
                'tax': totalTax,
                'total': totalAmount + totalTax
            });
        }
        else {
            totalAmount += Number(grid.jqGrid('getCell', id, 'amount'));
            totalTax += Number(grid.jqGrid('getCell', id, 'tax'));
        }
    }
}

提前致谢!

推荐答案

我发现您的代码中有两个问题.第一个更美观,但正确的解决方案可以简化未来的许多事情.

I see two problems in your code. The first one is more cosmetic, but the correct solution can simplify many things in the future.

第一个问题是您手动添加TOTAL"行作为网格数据的一部分,并在 calculateTotal 函数内计算行中的值.更好的方法是使用 footerrow:true 选项,它在网格底部添加额外的行,这将与网格数据不混合.对于基于服务器的数据,您可以使用来自服务器的 JSON 或 XML 响应的 userdata 部分,并另外使用 userDataOnFooter:true 来获取来自 userData 页脚行的 jqGrid 参数.如果是本地"数据类型,可以使用 footerData 方法设置(或获取)页脚中的数据.此外,方法 getCol 可用于计算元素的总和在列中.所以你的 calculateTotal 函数版本可以重写为

The first problem is that you add manual the "TOTAL" row as a part of grid data and calculate the values in the row inside calculateTotal function. The better way is to use footerrow:true option, which add additional row at the bottom of grid which will be not mixed with the grid data. For server based data you can use userdata part of JSON or XML response from the server and use userDataOnFooter:true additionally to till the data from the userData jqGrid parameter to the footer row. In case of "local" datatype one can use footerData method to set (or get) the data in the footer. Additionally the method getCol can be used co calculate the sum of elements in the column. So your version of calculateTotal function can be rewritten as

var grid = $("#list");
var calculateTotal = function() {
    var totalAmount = grid.jqGrid('getCol','amount',false,'sum'),
        totalTax = grid.jqGrid('getCol','tax',false,'sum');
    grid.jqGrid('footerData','set',{name:'TOTAL',amount:totalAmount,tax:totalTax});
}

现在是您的主要问题.您使用单元格编辑模式.如果函数 calculateTotal(您的原始版本或我的简化版本)将在金额"或税"的单元格中的一个处于编辑模式时被调用,则 calculateTotal 将被读取带有 <input> 元素的 HTML 片段,而不是带有数字的字符串,并且计算将失败.

Now to your main problem. You use cell edit mode. If the function calculateTotal (your original or my simplified version) will be called at the time when one from the cells of the 'amount' or 'tax' are in the editing mode, the calculateTotal will be read HTML fragment with <input> element instead of the string with the number and the calculation will failed.

我创建了 小演示,它调用了 calculateTotal 每秒.因此,如果您单击'amount' 或 'tax' 列,您将看到在页脚行 0 将显示为总和.因此,具有 cellsubmit:'clientArray' 的演示与使用 cellsubmit:'remote' 的原始代码存在相同的问题.

I created the small demo which call calculateTotal every second. So if you click on any cell from the 'amount' or 'tax' column you will see that in the footer row 0 will be displayed as the sum. So the demo having cellsubmit:'clientArray' has the same problem as in your original code with cellsubmit:'remote'.

为了解决这个问题,可以在求和时使用jqGrid的data参数:

To solve the problem one can use data parameter of jqGrid during the sum calculation:

var grid = $("#list");
var calculateTotal = function() {
    var gridData = grid.jqGrid('getGridParam','data'),
        i=0,totalAmount=0,totalTax=0;
    for (;i<gridData.length;i++) {
        var rowData = gridData[i];
        totalAmount += Number(rowData.amount);
        totalTax += Number(rowData.tax);
    }
    grid.jqGrid('footerData','set',{name:'TOTAL',amount:totalAmount,tax:totalTax});
}

您将在这里找到相应的固定演示.在您的最终代码中,您可以删除

The corresponding fixed demo you will find here. In your final code you can remove

setInterval(calculateTotal, 1000);

我仅用于演示目的并仅在 afterSaveCell 事件处理程序中刷新页脚.

which I used for demonstration purpose only and refresh the footer in the afterSaveCell event handler only.

已更新:如果您使用远程数据,则不能使用 data 参数.因此,如果需要,必须从 <input> 元素中获取数据.我创建了 另一个演示 来演示如何做到这一点.calculateTotal 的代码会更长:

UPDATED: If you work with remote data you can not use data parameter. So one have to get data from the <input> element if needed. I created one more demo which demonstrate how one can do this. The code of calculateTotal will be longer:

var getColumnIndexByName = function(grid,columnName) {
    var cm = grid.jqGrid('getGridParam','colModel');
    for (var i=0,l=cm.length; i<l; i++) {
        if (cm[i].name===columnName) {
            return i; // return the index
        }
    }
    return -1;
},
getTextFromCell = function(cellNode) {
    return cellNode.childNodes[0].nodeName === "INPUT"?
           cellNode.childNodes[0].value:
           cellNode.textContent || cellNode.innerText;
},
calculateTotal = function() {
    var totalAmount = 0, totalTax = 0,
        i=getColumnIndexByName(grid,'amount');
    $("tbody > tr.jqgrow > td:nth-child("+(i+1)+")",grid[0]).each(function() {
        totalAmount += Number(getTextFromCell(this));
    });

    i=getColumnIndexByName(grid,'tax');
    $("tbody > tr.jqgrow > td:nth-child("+(i+1)+")",grid[0]).each(function() {
        totalTax += Number(getTextFromCell(this));
    });

    grid.jqGrid('footerData','set',{name:'TOTAL',amount:totalAmount,tax:totalTax});
};

相关文章