调用“groupingGroupBy”函数会导致jqGrid进入无限循环。更好的建议?

时间:2013-10-07 18:19:50

标签: jqgrid

当脚本使用ajax从数据库中检索已保存的设置并使用它来填充jqGrid布局设置时。那是它进入无限循环的时候。经过一些研究,结果发现“groupingGroupBy”函数(在jqGrid源代码中)使用“reloadGrid”触发器,它与jqGrid的“beforeRequest”事件不能很好地混合。我欢迎更好的建议。感谢...

这是代码......

           $('#' + jqgridSpreadsheetId).jqGrid({
            url: jqgridWebUrl,
            datatype: 'json',
            mtype: 'POST',
            postData: { WhichJqgridTemplate: jqgridWhichTemplate },
            jsonReader: { repeatitems: false },
            colNames: ['', 'Id', 'Stock Number', 'VIN', 'Year', 'Make', 'Model', 'Trim', 'Mileage', 'Purchase Price', 'Stock Date', 'Repair Cost', 'Total Cost', 'Days In Inventory', 'Hidden-Inventory-Tracker-Location-Id', 'Inventory Tracker Location', 'Category', 'Links'],  //Display Text in Column Header...
            colModel: [
                       //jsonmap --> http://stackoverflow.com/questions/16396229/use-jqgrid-action-formatter...
                       //        --> http://stackoverflow.com/questions/6989608/jqgrid-inline-edit-rows-and-data-not-lining-up...
                       //        --> http://stackoverflow.com/questions/6364473/using-the-jsonmap-property-of-jqgrid-colmodel-with-untyped-json
                       //action-delete --> http://stackoverflow.com/questions/14732234/how-to-delete-row-in-jqgrid...
                       //In this case, use "sorttype" property in "colModel" for it to work when "loadonce" is set to true...
                       //formatter doc --> "http://www.trirand.com/jqgridwiki/doku.php?id=wiki:predefined_formatter&s[]=cell&s[]=formatter"...
                       //formatter hyperlink --> Stackoverflow posting was said to use formatter's function declaration instead of formatter's "showlink" followed by "formatoptions"...
                       //                    --> (Old Link) - http://stackoverflow.com/questions/5010761/linking-from-a-column-value-in-jqgrid-to-a-new-page-using-get...
                       //                    --> (New Link) - http://stackoverflow.com/questions/14529358/jqgrid-need-hyperlink-need-to-capture-value-through-jquery/14537512#14537512...
                       //                    --> (New Link) - http://www.trirand.com/jqgridwiki/doku.php?id=wiki:custom_formatter...
                       //                    --> Reasons are --> 1) far simpiler to use formatter for reading/writing and 2) much quicker and better performance...
                       {
                           jsonmap: function (o) { return ''; }, name: 'actDelete', index: 'actDelete', width: 40, align: 'center', sortable: false, hidedlg: true, formatter: 'actions',  //"hidedlg" is use to hide the hidden column in "Column Chooser"...
                           formatoptions: {
                               keys: false, editbutton: false,
                               //http://stackoverflow.com/questions/11897649/cant-refresh-jqgrid-with-loadonce-true...  (This show us how to reload jqGrid on edit/delete/add, the easy way, when using loadonce:true)...
                               delOptions: {
                                   url: jqgridWebUrl,
                                   mtype: 'POST',
                                   onclickSubmit: function (objects, rowid) { return { WhichJqgridTemplate: jqgridWhichTemplate, WebpageVehicleVin: $(this).getCell(rowid, jqgridColumnIdVin), WebpageReason: $('textarea[id=#' + jqgridDialogDeleteTextareaId + ']').val() } },
                                   width: 600,
                                   errorTextFormat: function (response) { return "<div style='text-align:center;padding:3px 0px 3px 0px;'>Unable to delete vehicle from Inventory due to an internal error</div>"; },
                                   beforeShowForm: function ($form) {
                                       //http://stackoverflow.com/questions/10035911/jqgrid-inline-delete-selected-row-selrow-is-incorrect...  (showed how to use "rowIdOfDeletedRow" in inline-delete dialog)...
                                       //http://stackoverflow.com/questions/6913618/jqgrid-custom-delete-dialog-message...  (showed how to customize the inline-delete's message)...
                                       var rowIdOfDeletedRow = $('#DelData>td:nth-child(1)').text();
                                       //Override delete wording message w/ custom message...
                                       $('td.delmsg', $form[0]).html("<div style='padding-top:5px;text-align:center;'>Delete &quot;" + $(this).getCell(rowIdOfDeletedRow, jqgridColumnIdYear) + " " + $(this).getCell(rowIdOfDeletedRow, jqgridColumnIdMake) + " " + $(this).getCell(rowIdOfDeletedRow, jqgridColumnIdModel) + " " + $(this).getCell(rowIdOfDeletedRow, jqgridColumnIdTrim) + "&quot; vehicle record?</div>");
                                       //Check to see if textarea exists, if not then create one...
                                       if ($('table.DelTable tr:last td textarea[id=#' + jqgridDialogDeleteTextareaId + ']').length == 0) {
                                           $('table.DelTable tr:last').after('<tr><td style="padding-bottom:10px;vertical-align:top;">Reasons: <textarea id="#' + jqgridDialogDeleteTextareaId + '" rows="2" cols="20" style="width:400px;height:60px;" /></td></tr>');  //display:table-cell;vertical-align:top;...
                                       } else { $('textarea[id=#' + jqgridDialogDeleteTextareaId+']').val(''); }
                                   },
                                   resize: false,
                               }
                           },
                           search: false
                       },  //"hidedlg" is use to hide the hidden column in "Column Chooser"...  //"search" is use to hide the field in search dialog...
                       { jsonmap: function (o) { return o.cell[0]; }, name: 'Id', index: 'Id', sortable: false, width: 0, align: 'left', hidden: true, hidedlg: true, search: false },  //"search" is use to hide the field in search dialog, "hidedlg" is use to hide the hidden column in "Column Chooser"...
                       { jsonmap: function (o) { return o.cell[1]; }, name: 'StockNumber', index: 'StockNumber', sorttype: 'text', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
                       { jsonmap: function (o) { return o.cell[2]; }, name: 'Vin', index: 'Vin', sorttype: 'text', width: 190, align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
                       { jsonmap: function (o) { return o.cell[3]; }, name: 'Year', index: 'Year', sorttype: 'int', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
                       { jsonmap: function (o) { return o.cell[4]; }, name: 'Make', index: 'Make', sorttype: 'text', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
                       { jsonmap: function (o) { return o.cell[5]; }, name: 'Model', index: 'Model', sorttype: 'text', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
                       { jsonmap: function (o) { return o.cell[6]; }, name: 'Trim', index: 'Trim', sorttype: 'text', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
                       { jsonmap: function (o) { return o.cell[7]; }, name: 'Mileage', index: 'Mileage', sorttype: 'int', align: 'center', formatter: 'number', formatoptions: { decimalSeparator: '', thousandsSeparator: ',', decimalPlaces: 0, defaultValue: '0' } },
                       { jsonmap: function (o) { return o.cell[8]; }, name: 'PurchasePrice', index: 'PurchasePrice', sorttype: 'currency', align: 'center', formatter: 'currency', formatoptions: { decimalSeparator: '.', thousandsSeparator: ',', decimalPlaces: 2, defaultValue: '0.00', prefix: '$', suffix: '' } },
                       { jsonmap: function (o) { return o.cell[9]; }, name: 'StockDate', index: 'StockDate', sorttype: 'date', align: 'center', formatter: 'date', formatoptions: { newformat: 'm/d/Y' } },  //"formatter" and "formatoptions" is required for date sorting to works properly...
                       { jsonmap: function (o) { return o.cell[10]; }, name: 'RepairCost', index: 'RepairCost', sorttype: 'currency', align: 'center', formatter: 'currency', formatoptions: { decimalSeparator: '.', thousandsSeparator: ',', decimalPlaces: 2, defaultValue: '0.00', prefix: '$', suffix: '' } },
                       { jsonmap: function (o) { return o.cell[11]; }, name: 'TotalCost', index: 'TotalCost', sorttype: 'currency', align: 'center', formatter: 'currency', formatoptions: { decimalSeparator: '.', thousandsSeparator: ',', decimalPlaces: 2, defaultValue: '0.00', prefix: '$', suffix: '' } },  /*summaryType:'sum' is needed for column grouping to work...*/
                       { jsonmap: function (o) { return o.cell[12]; }, name: 'DaysInInventory', index: 'DaysInInventory', sorttype: 'int', align: 'center', formatter: 'number', formatoptions: { decimalSeparator: '', thousandsSeparator: ',', decimalPlaces: 0, defaultValue: '1' } },
                       { jsonmap: function (o) { return o.cell[13]; }, name: 'InventoryTrackerLocationId', sortable: false, width: 0, align: 'left', hidden: true, hidedlg: true, search: false },  //"search" is use to hide the field in search dialog, "hidedlg" is use to hide the hidden column in "Column Chooser"...
                       { jsonmap: function (o) { return o.cell[14]; }, name: 'InventoryTrackerLocation', index: 'InventoryTrackerLocation', sorttype: 'text', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
                       { jsonmap: function (o) { return o.cell[15]; }, name: 'Category', index: 'Category', sorttype: 'text', align: 'center', searchoptions: { sopt: ['eq', 'ne'] } },
                       //Links is not present in json data from the website, so we customize it here...
                       { jsonmap: function (o) { return ''; }, name: 'Links', index: 'Links', sortable: false, width: 80, align: 'center', hidedlg: true, formatter: function (cellValue, options, rowObject) { return "<span style='text-decoration:underline;cursor:pointer;'>Links</span>" }, search: false }  //"search" is use to hide the field in search dialog, "hidedlg" is use to hide the hidden column in "Column Chooser"...
            ],
            pager: '#'+jqgridPagerId,
            rowNum: 1000000000,  //-1, //10,  //06/13/2013 - It is reported that the use of "-1" broke jqGrid when loadonce:true is used.  Alternatively, use the max # of rows...
            //#rowList: //[5, 10, 20, 50],  //Page size dropdown in footer - To show how many rows per page...
            rowList: [],  //Disable page size dropdown...
            pgbuttons: false,  //Disable page control like next, back button...
            pgtext: null,  //Disable pager text line like "Page 0 of 10"...
            viewrecords: false,  //Disable current view record text like 'View 1-10 of 100'...
            caption: 'My Inventory',
            width: jqgridLayoutWidth,
            shrinkToFit: false,  /* This is not reliable */
            forceFit: false,  /* This is not reliable, plus it it wouldn't work if shrinkToFit is set to false... */
            autoWidth: false,
            cellLayout: 0,  /* This defaulted to 5, so we need to set it to 0 for custom css to works better */
            height: 400,
            sortable: false,  /* Do not allow header-column to shift sideway..  Makes it harder for draggable Group-Header-Column features to work... */  /* Discontinued - This allows both 1) Moving columns sideway to other location fields and 2) for jqGrid Column Chooser Plugin / JQuery Multiselect Plugin to work... */
            grouping: true,  /* This allows row data to be group into row grouping... */
            loadonce: false,  /* 06/10/2013 - Set it to false from now on...  It is learned that having loadonce:true is not worth the trouble when using search feature, delete feature, etc. so we're better off having client-side do both 1) jqGrid ajaxGridOption and 2) server-side querying to do the heavy work for us... */
            //emptyrecords: "No records to display",
            ajaxGridOptions: {
                beforeSend: function (xhr) { ftnThrobblerAnimationBegin2(); },
                complete: function (xhr) { ftnThrobblerAnimationEnd2(); },
                error: function (xhr) { alert("An error had occurred, please try again or notify webmaster of this error"); ftnThrobblerAnimationEnd2(); }
            },
            loadComplete: function () {
                JqgridSummarySpreadsheetDisplay();
                JqgridGroupedColumnsFormatter();
            },
            //#loadBeforeSend: function (xhr, settings) {  /*Notice: A pre-callback to modify the ajax request object (XMLHttpRequest - xhr) before it is sent.  Use this to set custom headers etc. Returning false will cancel the request...*/ },
            beforeRequest: function () {
                //JqgridColumnChooserSavedBuildsRecordsSetup("INIT", "4444");
                $('#' + jqgridSpreadsheetId).jqGrid('groupingGroupBy',
                    "Make,Model",
                    {
                        groupCollapse: true,
                        groupField: ['name']//,
                        //08/16/2013 - Appearantly, this "groupText" object is broken and doesn't allow adding "groupText"'s value to recursive grouped column's "groupText" starting with 2nd grouped Columns and after...
                        //           - Use the "jqgridGroupedColumnsFormatter()" function instead under the jqGrid's "loadComplete" attribute...
                        //groupText: ["<span style='float:left;font-weight:bold;'>{0} - ({1})</span><span style='float:right;font-weight:bold;'> </span>"]
                    }
                );
            }
        });

示例1

$('#test').jqGrid({
   //.....,
   loadComplete: function() { 
       /* ... */ 
   },
   beforeRequest: function() {
       /* ... */
   },
   grouping: true,
   groupingView: {
       groupField: ["Make","Model"],
       groupCollapse: true
   }
});

示例2

$('#test').jqGrid({
   //.....,
   loadComplete: function() { 
       /* ... */ 
   },
   beforeRequest: function() {
      $(this).jqGrid('setGridParam', {
         grouping: true,
         groupingView: {
            groupField: ["Make","Model"],
            groupCollapse: true
         }
      });  //.trigger('reloadGrid');
   },
});

示例3

$('#test').jqGrid({
   //.....,
   loadComplete: function() { 
      $(this).jqGrid('setGridParam', {
         grouping: true,
         groupingView: {
            groupField: ["Make","Model"],
            groupCollapse: true
         }
      });  //.trigger('reloadGrid');
   },
   beforeRequest: function() {
       /* ... */ 
   },
});

示例4

$('#test').jqGrid({
   //.....,
   loadComplete: function() { 
       /* ... */ 
   },
   beforeRequest: function() {
       /* ... */ 
   },
   beforeProcessing: function() { 
      $(this).jqGrid('setGridParam', {
         grouping: true,
         groupingView: {
            groupField: ["Make","Model"],
            groupCollapse: true
         }
      });  //.trigger('reloadGrid');
   }
});

示例5

var blockInfiniteLoopCounter = 0;

$('#test').jqGrid({
   //.....,
   loadComplete: function() { 
       /* ... */ 
   },
   beforeRequest: function() {
       /* ... */ 
   },
   beforeProcessing: function() { 
      if (blockInfiniteLoopCounter == 0) {
          blockInfiniteLoopCounter++;

         $(this).jqGrid('setGridParam', {
            grouping: true,
            groupingView: {
               groupField: ["Make","Model"],
               groupCollapse: true
            }
         }).trigger('reloadGrid');
      }
   }
});

示例6

        var $grid = $("#list");

           $grid.jqGrid({
               datatype: 'json',
               url: 'MyInventory-Testcase2.json',
               jsonReader: {
                   repeatitems: false,
                   id: "Id",
                   root: function (obj) { return obj; },
                   page: function () { return 1; },
                   total: function () { return 1; },
                   records: function (obj) { return obj.length; }
               },
               loadonce: true,
               colNames: ['Client', 'Date', 'Amount', 'Tax', 'Total', 'Closed', 'Shipped via', 'Notes'],
               colModel: [
            {name: 'name', width: 65},
            {name: 'invdate', width: 80, align: 'center', sorttype: 'date',
                formatter: 'date', formatoptions: {newformat: 'd-M-Y'}, datefmt: 'd-M-Y',
                searchoptions: { sopt: ['eq', 'ne', 'lt', 'le', 'gt', 'ge'] }},
            {name: 'amount', width: 75, },
            {name: 'tax', width: 52, },
            {name: 'total', width: 65, },
            {name: 'closed', width: 80, align: 'center', formatter: 'checkbox',
                edittype: 'checkbox', editoptions: {value: 'Yes:No', defaultValue: 'Yes'},
                stype: 'select',
                searchoptions: {
                    sopt: ['eq', 'ne'],
                    value: 'true:Yes;false:No'
                }},
            {name: 'ship_via', width: 100, align: 'center', formatter: 'select',
                edittype: 'select',
                editoptions: {
                    value: 'FE:FedEx;TN:TNT;IN:Intim',
                    defaultValue: 'Intime'
                },
                stype: 'select',
                searchoptions: {
                    sopt: ['eq', 'ne'],
                    value: 'FE:FedEx;TN:TNT;IN:Intim'
                }},
            {name: 'note', width: 100, sortable: false}
               ],
               cmTemplate: {editable: true},
               rowNum: 10,
               rowList: [5, 10, 20],
               pager: '#pager',
               gridview: true,
               ignoreCase: true,
               rownumbers: false, //true,
               sortname: 'invdate',
               viewrecords: true,
               sortorder: 'desc',
               height: '100%',
               caption: 'Set grouping dynamically',
               beforeProcessing: function() {
               //beforeRequest: function() {
               //loadComplete: function() {
                   $(this).jqGrid('setGridParam', {
                       //grouping: true,
                       groupingView: { groupCollapse: true, groupField: ["name", "amount"] }
                       //});  //#.trigger('reloadGrid');
                   });
               }
           });

           $("#dynamicGrouping").change(function () {
               var groupingName = $(this).val();
               if (groupingName) {
                   //$grid.jqGrid('groupingGroupBy', groupingName);
                   $grid.jqGrid('groupingGroupBy', groupingName, {
                       // groupField : [groupingName],
                       groupOrder : ['desc'],
                       groupColumnShow: [false],
                       //groupDataSorted : true,
                       groupCollapse: true
                   });
               } else {
                   $grid.jqGrid('groupingRemove');
               }
           });

1 个答案:

答案 0 :(得分:1)

示例2出现以下错误:您使用不需要的{...}。代码beforeRequest: function() {$('#test').jqGrid({'setGridParam', {...}});}应替换为beforeRequest: function() {$(this).jqGrid('setGridParam', {...});}

我仍然认为使用静态 groupField值没有任何意义。如果您在服务器上保存有关groping 的数据,我会发现服务器返回有关用户分组首选项的信息作为服务器响应的一部分。在这种情况下,您可以使用beforeProcessing回调来分析服务器响应的相应部分,并设置jqGrid的groupinggroupingView选项。

更新:在设置新的groupingSetup选项后,可以通过额外调用groupingView方法修复示例6:

beforeProcessing: function () {
    var $this = $(this);
    $(this).jqGrid("setGridParam", {
        grouping: true,
        groupingView: {
            groupCollapse: true,
            groupField: ["name", "amount"]
        }
    });
    $this.jqGrid("groupingSetup");
}

我准备了the corresponding demo。我在演示中使用以下格式的JSON数据

{
    "groupField": ["name", "amount"],
    "rows": [
        { "id": "1",  "name": "test", ... },
        { "id": "2",  "name": "test2", ... },
        ...
        { "id": "12", "name": "test12", ... }
    ]
}

以及以下beforeProcessing

beforeProcessing: function (data) {
    var $this = $(this);
    $(this).jqGrid("setGridParam", {
        grouping: ($.isArray(data.groupField) && data.groupField.length > 0) ?
                  true :
                  false,
        groupingView: {
            groupCollapse: true,
            groupField: data.groupField //["name", "amount"]
        }
    });
    $this.jqGrid("groupingSetup");
}

所以我从服务器响应中获取分组字段([“name”,“amount”])。