jqGrid получает доступ к данным ячейки во время их редактирования

В настоящее время я использую afterSaveCell для ручного обновления некоторых ячеек в сетке. У меня это работает нормально, если пользователь использует ввод, чтобы сохранить текущую редактируемую ячейку.

К сожалению, если они щелкнут или выйдут из ячейки, которую они редактируют, непосредственно в другую ячейку, я больше не смогу получить значение ячейки только что отредактированной ячейки, поскольку getCell вернет только html для элемента управления вводом.

Таким образом, есть ли способ получить доступ к значению ячейки даже во время ее редактирования?

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

Заранее спасибо!


person Shawn    schedule 25.02.2011    source источник
comment
Если вам нужно сохранить текущую ячейку на TAB, вы будете перезаписывать реализацию по умолчанию nextCell и prevCell, которые будут вызываться на TAB или Shift-TAB. См. код функций здесь: github.com/ tonytomov/jqGrid/blob/master/js/   -  person Oleg    schedule 25.02.2011
comment
Спасибо @Oleg, это определенно помогло бы решить проблему TAB, но по-прежнему оставляет проблему при размытии на другую ячейку в той же сетке.   -  person Shawn    schedule 26.02.2011
comment
Вы правы насчет размытия. Вероятно, способ привязки элемента редактирования к событию «размытие» или даже «фокусировка» может решить вашу проблему. Вы можете использовать dataEvents (см. ячейку и манипулировать ею">stackoverflow.com/questions/4407273/) в editoptions, чтобы сделать привязку к событию focusout и вызвать saveCell. Вы можете дополнительно использовать beforeEditCell для сохранения последних iRow, iCol необходимых параметров в файле saveCell.   -  person Oleg    schedule 26.02.2011
comment
Я перечитал ваш вопрос еще раз и не уверен, что правильно понял вас раньше. Мне кажется, что вы хотите просто иметь доступ к ячейке, содержащейся внутри специального события. Не имея кода, который более четко описывает вашу проблему, я, вероятно, не смогу вам помочь.   -  person Oleg    schedule 26.02.2011
comment
Я попытался создать пример, используя clientArray, но он не воспроизводит ошибку. Кажется, что задержка при отправке новых данных ячейки на сервер вызывает создание поля ввода до вызова afterSaveCell. В примере clientArray, без отправки на сервер, afterSaveCell вызывается до того, как только что отредактированные данные ячейки преобразуются во входные данные. Мне нужно немного больше времени, чтобы создать правильный пример.   -  person Shawn    schedule 26.02.2011
comment
@ Олег, я создал пример, который вы можете увидеть здесь. Если вы попытаетесь отредактировать столбцы Amount или Tax, а затем щелкнете по другому столбцу после редактирования, вновь переключенный на итог изменится на 0,00 вместо правильного итога. Это происходит потому, что ячейка, которую вы сейчас редактируете, возвращает элемент управления вводом getCell вместо значения ячейки. Происходит это из-за задержки с удаленным cellsubmit. Использование локального clientArray не вызывает этой проблемы.   -  person Shawn    schedule 26.02.2011
comment
@Shawn: Теперь я хорошо понимаю твою проблему. Надеюсь, я предложу решение проблемы, которое напишу в качестве ответа на ваш вопрос.   -  person Oleg    schedule 26.02.2011
comment
@Shawn: Мне кажется, что проблема доступа к ячейкам, которые находятся в режиме редактирования, является общей проблемой, которая может возникнуть у других людей. Было бы неплохо, если бы вы изменили текст своего вопроса с помощью информации из ваших комментариев, чтобы другим людям было легче читать ваш вопрос.   -  person Oleg    schedule 27.02.2011
comment
@Shawn: я внес небольшие изменения в код демонстраций, чтобы не использовать глобальные функции. Как известно, использование глобальной функции происходит медленнее и может привести к потенциальным конфликтам имен.   -  person Oleg    schedule 27.02.2011


Ответы (3)


Я вижу две проблемы в вашем коде. Первый более косметический, но правильное решение может многое упростить в будущем.

Первая проблема заключается в том, что вы вручную добавляете строку «ИТОГО» как часть данных сетки и вычисляете значения в строке внутри функции calculateTotal. Лучше использовать опцию footerrow:true, которая добавляет дополнительную строку внизу сетки, которая не смешивается с данными сетки. Для серверных данных вы можете использовать userdata часть ответа JSON или XML от сервера и использовать userDataOnFooter:true дополнительно для передачи данных из параметра userData jqGrid в строку нижнего колонтитула. В случае "локального" типа данных можно использовать метод footerData для установить (или получить) данные в нижнем колонтитуле. Кроме того, для вычисления суммы элементов можно использовать метод getCol. в колонке. Таким образом, ваша версия функции calculateTotal может быть переписана как

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 будет прочитан фрагмент HTML с элементом <input> вместо строка с числом, и расчет не будет выполнен.

Я создал небольшую демонстрацию, которая вызывает calculateTotal каждую секунду. Поэтому, если вы щелкнете по любой ячейке в столбце «сумма» или «налог», вы увидите, что в строке нижнего колонтитула 0 будет отображаться как сумма. Таким образом, демо с cellsubmit:'clientArray' имеет ту же проблему, что и ваш исходный код с cellsubmit:'remote'.

Для решения проблемы можно использовать параметр data jqGrid при вычислении суммы:

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

Соответствующую фиксированную демонстрацию вы найдете здесь. В вашем окончательном коде вы можете удалить

setInterval(calculateTotal, 1000);

который я использовал только для демонстрации и обновлял нижний колонтитул только в обработчике событий afterSaveCell.

ОБНОВЛЕНО: если вы работаете с удаленными данными, вы не можете использовать параметр data. Таким образом, при необходимости нужно получить данные из элемента <input>. Я создал еще одно демо, демонстрирующее, как это можно сделать. Код calculateTotal будет длиннее:

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});
};
person Oleg    schedule 26.02.2011
comment
Похоже, что jqGrid('getGridParam','data') работает только с локальными данными. Использование его с моими удаленными данными json возвращает пустую строку. - person Shawn; 27.02.2011
comment
@Shawn: Да, это правильно, но в вашей демонстрации использовались локальные данные. Если вам нужно использовать удаленные данные, вы должны проверить, являются ли данные из getCell фрагментом HTML с <input> или нет. Вместо перечисления идентификаторов строк вы можете использовать более быстрый способ jQuery, который я описал stackoverflow.com/questions/5010761/. Чтобы упростить вам задачу, я создал еще одну демонстрацию ok-soft-gmbh.com/jqGrid. /CellEditAfterSaveCellProblem1.htm, которые делают то, что вам нужно. - person Oleg; 27.02.2011
comment
@Олег: отличный ответ! У меня есть еще один вопрос - в моей строке есть ячейка типа выбора - как я могу суммировать общую сумму только тогда, когда выбранное значение является первым значением внутри нее? Я имею в виду, что хочу вычислить сумму в зависимости от значения внутри выбранной ячейки. Благодарность.. - person user590586; 15.05.2011
comment
@ user590586: Вам придется расширить код getTextFromCell. Я действительно не понимаю, как вы хотите вычислить сумму элементов select, потому что select обычно содержит тексты, а не целые числа. - person Oleg; 15.05.2011
comment
@Олег: сумма не в выбранной ячейке, а в другой ячейке. то, что я хочу сделать, это суммировать эту сумму, только если у меня есть определенное значение внутри выбранной ячейки. ты понимаешь, что я пытаюсь сделать? Является ли это возможным? - person user590586; 15.05.2011
comment
@ user590586: Было бы лучше, если бы вы предоставили сетку с соответствующими данными и сформулировали вопрос, где вы точно описываете, какой критерий фильтра вам нужно использовать. - person Oleg; 15.05.2011
comment
@Oleg: это ячейка выбора: {имя: 'статус', индекс: 'статус', ширина: 90, тип сортировки: int, редактируемый: правда, тип редактирования: выбор, форматер: 'выбрать', варианты редактирования: {значение: 1 :подтверждено ;2:открыто ; 3: Отклонено, dataInit: function(elem){$(elem).widt(90);}}}, я хочу рассчитать ячейку общей суммы, только если значение внутри выбора подтверждено. (ячейка суммы, как в вопросе). Вам нужны еще данные? - person user590586; 15.05.2011
comment
@ user590586: Я могу только повторить, что вы должны открыть новый вопрос и опубликовать всю информацию. Тогда у меня будет достаточно места, чтобы написать ответ, и другие люди с близкими требованиями смогут найти мой ответ. - person Oleg; 15.05.2011
comment
@ user590586: Хорошо! Я постараюсь сделать новое демо и опубликовать его как ответ на вопрос. - person Oleg; 15.05.2011

Спасибо олег, решение для меня было применить и изменить то, что вы поставили

var ListTabla="ListFormatos";
var request="../../tabla_general/tabla_general_mantenimiento.php";

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(grid) {   

total_hpr_suebas = retorna_suma('hpr_suebas',grid);
total_hpr_asifam = retorna_suma('hpr_asifam',grid);
total_hpr_bashpr = retorna_suma('hpr_bashpr',grid);
total_hpr_remcom = retorna_suma('hpr_remcom',grid);
total_hpr_basmes = retorna_suma('hpr_basmes',grid);
total_hpr_provcts = retorna_suma('hpr_provcts',grid);
total_hpr_provgrat = retorna_suma('hpr_provgrat',grid);
total_hpr_provvac=retorna_suma('hpr_provvac',grid);

    $("#"+grid).jqGrid('footerData','set',{sec_detsec:'TOTAL',hpr_suebas:total_hpr_suebas,hpr_asifam:total_hpr_asifam,hpr_bashpr:total_hpr_bashpr,hpr_remcom:total_hpr_remcom,hpr_basmes:total_hpr_basmes,hpr_provcts:total_hpr_provcts,hpr_provgrat:total_hpr_provgrat,hpr_provvac:total_hpr_provvac});
};

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

function fn_jqgrid_history_provisiones_trabajador(tra_idtra,fecha_inicio,fecha_fin)
{
    jQuery("#"+ListTabla).jqGrid({
                    url:request+"?action=search_history_provisiones_trabajador&tra_idtra="+tra_idtra+"&fecha_inicio="+fecha_inicio+"&fecha_fin="+fecha_fin,
                    async: false,
                    datatype: 'json',
                    colNames:['','ID','SECTOR','BASICO','ASIG. FAM','DIAS','BASE','REM. COMP.','BASE MES','P.CTS','P.GRAT.','P.VAC.','MES','ANIO','PORC.','SAL.VAC.','SAL.GRAT.'],
                    colModel:[
                         {name:'act', index:'act', width:50, resizable:true, align:"center",hidden:true},
                        {name:'id', index:'id', width:50, resizable:true, align:"center",hidden:true},
                        {name:'sec_detsec', index:'sec_detsec', width:80},
                        {name:'hpr_suebas', index:'hpr_suebas', width:60},
                        {name:'hpr_asifam', index:'hpr_asifam', width:50},
                        {name:'hpr_numdia', index:'hpr_numdia', width:30},
                        {name:'hpr_bashpr',index:'hpr_bashpr', width:60},
                        {name:'hpr_remcom,',index:'hpr_remcom', width:60},
                        {name:'hpr_basmes', index:'hpr_basmes', width:60},
                        {name:'hpr_provcts', index:'hpr_provcts', width:60},
                        {name:'hpr_provgrat', index:'hpr_provgrat', width:60},
                        {name:'hpr_provvac', index:'hpr_provvac', width:60},
                        {name:'hpr_meshpr', index:'hpr_meshpr', width:30},
                        {name:'hpr_aniohpr,',index:'hpr_aniohpr', width:30},
                        {name:'hpr_salpor', index:'hpr_salpor', width:50},
                        {name:'hpr_salval_vac', index:'hpr_salval_vac', width:50},
                        {name:'hpr_salval_grat', index:'hpr_salval_grat', width:50}
                    ],
                    pager: '#paginacion',
                    rowNum:10,
                    rowList:[10,20,30],
                    sortname: 'ID',
                    ondblClickRow:function(rowid, iRow, iCol, e)
                    {
                                obj=jQuery("#"+ListTabla).jqGrid('getRowData',rowid);
                    }
                    ,
                    sortorder: 'desc',
                    editurl:request,
                    viewrecords: true,
                    caption: 'Provisiones',
                    //rownumbers: true,
                     height: 250,
                    rowheight: 280,
                    footerrow : true,
                    gridComplete: function () {
                        calculateTotal(ListTabla);
                },
                    afterSaveCell: function (rowid, name, val, iRow, iCol) {
                        //calculateTotal(ListTabla);
                    }
                    }).navGrid('#paginacion',{add:false,edit:false, del:false});

                        jQuery("#"+ListTabla).jqGrid('bindKeys', {"onEnter":function( rowid ) {
                                                                    obj=jQuery("#"+ListTabla).jqGrid('getRowData',rowid);
                                                                    } } );  

                 }
person user1413147    schedule 23.05.2012

Если вы просто хотите пересчитать общее количество, вы можете использовать триггер для перезагрузки сетки в событии afterSaveCell. Нравится:

afterSaveCell: function (rowid, name, val, iRow, iCol) 

        {
          jQuery("#list11").jqGrid('setGridParam',{datatype:'local',loadonce:true}).trigger('reloadGrid');
        }
person Julia    schedule 06.11.2012