jqGrid iterate over the grid Data in a subgrid

I would like to iterate all over the data contained in grid object. My grid has a definition that include a subgrid object and is created this way

var grid = $(gridID);
var pager = $(pagerID);
grid.jqGrid({
    url: GetBaseWSUrl() + 'MyWs.asmx/MyMethod',
    colNames: ['UMLT', 'FF', 'PC'],
    colModel: [
            { name: 'Name', index: 'Name', width: 180, template: colTextTemplate },
            { name: 'AlertFF', index: 'AlertFF', width: 22, align: 'center', sortable: false, formatter: "checkbox", formatoptions: { disabled: false} },
            { name: 'AlertPC', index: 'AlertPC', width: 22, align: 'center', sortable: false, formatter: "checkbox", formatoptions: { disabled: false} }
        ],
    [...]
    subGrid: true,
    subGridOptions: {
        "plusicon": "ui-icon-triangle-1-e",
        "minusicon": "ui-icon-triangle-1-s",
        "openicon": "ui-icon-arrowreturn-1-e",
        "reloadOnExpand": true,
        "selectOnExpand": true
    },
    subGridRowExpanded: function (subgrid_id, row_id) {
        var subgrid_table_id = subgrid_id + "_t";
        $("#" + subgrid_id).html("<table id='" + subgrid_table_id + "' class='scroll'></table>");
        $("#" + subgrid_table_id).jqGrid({
            [...] omitted for brevity
        });
    }
});

I know I can use code like this one to iterate on the data, and effectively it works for the first level but I am looking for a method that will permit me to iterate even on the subgrid data.

var grid = $('#grid');
var m = grid.getDataIDs();
for (var i = 0; i < m.length; i++) {
    var record = grid.getRowData(m[i]);
    //do something with the record
}

Is there any way to accomplish this?


Solution 1:

OK. In the answer and in this one I describe how to enumerate the grid rows mostly effectively. Probably if you works more with jQuery and not with DOM the code will looks strange for you. I received questions whether it is safe to use the DOM elements? Is it not better to use jQuery instead? So I before all I try to answer on the questions and explain why I think it's the best way. If you have an interest only in the result code and not in the explanation you can skip the part of my answer.

The main idea is that $('#grid') is a jQuery wrapper to the HTML DOM <table> object. The table DOM object (HTMLTableElement) $('#grid')[0] has rows property which is collection of grid rows: collection of <tr> DOM elements (HTMLTableRowElement). One can iterate the grid rows per index: $('#grid')[0].rows[i] which starts with 0. If one knows the rowid (the id of the <tr> element) then one can get the corresponding <tr> DOM object with respect of $('#grid')[0].namedItem[rowid]. So the rows is collection of DOM elements having cells property. If you want to examine the contain of the j-th column of the i-th row of the grid you can get the <td> element directly by $('#grid')[0].rows[i].cells[j]. If you know only the column name you can examine colModel array and search for the column having the name property which you need. If index in the colModel array is j you can use the index in the $('#grid')[0].rows[i].cells[j] expression.

Important is that rows collection and namedItem method are parts of W3C standard (see here and here). So it's really safe to use there. All browsers fill the rows collection and all browsers has native code (!!!) which implement quick indexing in rows collection and quick searching in the collection by id (I mean the namedItem method). jqGrid internally use these permanently and it is the reason why jqGrid works quickly. The jQuery is JavaScript library which use internally DOM. It can be not so quickly as native browser code. In some situations like calculation of position or width there are many tricks to get the information correctly in all web browsers, but working with HTML table DOM is W3 standard and the usage of jQuery here gives you no advantages.

In some my old answers I used code grid.getDataIDs() and for by the ids. Now I would suggest you to follow the code from the answer. One only remark about subgrids and other rows.

jqGrid has 4 types of <tr> elements which has 4 different classes. So you can examine the classes of <tr> elements to determine whether the row contains subgrid, grouping header, standard row or hidden first row used internally to set the width of the columns.

var grid = $('#grid')[0], rows = grid.rows,
    cRows = rows.length, iRow, row, trClasses;

    for (iRow = 0; iRow < cRows; iRow++) {
        row = rows[iRow]; // row.id is the rowid
        trClasses = row.className.split(' ');
        if ($.inArray('jqgrow', trClasses) > 0) {
            // the row is a standard row
        } else if ($.inArray('ui-subgrid', trClasses) > 0) {
            // the row contains subgrid (only if subGrid:true are used)
        } else if ($.inArray('jqgroup', trClasses) > 0) {
            // the row is grouping header (only if grouping:true are used)
        } else if ($.inArray('jqfoot', trClasses) > 0) {
            // the row is grouping summary (only if grouping:true are used)
            // and groupSummary: [true] inside of groupingView setting
        } else if ($.inArray('jqgfirstrow', trClasses) > 0) {
            // the row is first dummy row of the grid. we skip it
        }
    }

Now if you have row which is standard grid row you can examine the checkbox from the column having 'AlertFF' name. First of all you should get the index of the column ones (outside of the loop). You can use small getColumnIndexByName method from the answer: var iCol = getColumnIndexByName($('#grid'), 'AlertFF'). Now inside of the body of if ($.inArray('jqgrow', trClasses) > 0) you can do

if ($.inArray('jqgrow', trClasses) > 0) {
    if ($(row.cells[iCol]).children("input:checked") > 0) {
        // the checkbox in the column is checked
    }
}

To examine the data from subgrid as grid which you use you can do following

...
} else if ($.inArray('ui-subgrid', trClasses) > 0) {
    // the row contains subgrid
    var subgridTable = $(row).find("table.ui-jqgrid-btable:first");
    // you can work with the subgridTable like with a grid
}

In the way you get subgridTable which has the same structure like $('#grid') from which we started. You can examine the contain of subgrid like I described before.