2

When the script used ajax to retrieve saved setting from the database and use it to populate the jqGrid layout setting. That's when it go into infinite loop. Upon some research, it turned out the "groupingGroupBy" function (in jqGrid source code) use "reloadGrid" trigger which doesn't mix well with jqGrid's "beforeRequest" event. I welcome better suggestion. Thanks...

Here's the code...

           $('#' + 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>"]
                    }
                );
            }
        });

Example 1

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

Example 2

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

Example 3

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

Example 4

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

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

Example 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');
               }
           });
fletchsod
  • 3,560
  • 7
  • 39
  • 65
  • Sorry, but I don't understand why you use `groupingGroupBy` inside of `beforeRequest`. What you try to do? Why you don't just use `groupingView` options of jqGrid directly? – Oleg Oct 07 '13 at 18:31
  • I was trying to load the jqGrid 1st, then use ajax to grab the selected saved data from database for it to populate the multilevel grouping during loading. The customer can save as many options they want to the database then use the default saved data (select one) to display the webpage result. The groupingView seem to be static and not know the saved data beforehand. – fletchsod Oct 07 '13 at 19:33
  • Sorry, but the code which you posted contains also *static* value `groupField: ['name']`. Moreover the parameter `"Make,Model"` of `groupingGroupBy` seems me wrong and it will be overwritten by `['name']`. Typically one don't use any other properties as `groupField` in the second parameter of `groupingGroupBy`. By which columns you want group the grid? – Oleg Oct 07 '13 at 20:08
  • Really... I saw the "Make,Model" value when debugging when I grouped those 2 columns. "By which columns you want group the grid", for starter, Make and Model column. – fletchsod Oct 07 '13 at 20:15
  • Also, when a webpage load for the 1st time, it can be either "no multilevel grouping" or "multilevel grouping" depending on whether the the group-by exists in the saved database data or not. – fletchsod Oct 07 '13 at 20:26
  • If you want to group by Make and Model column you should use `["Make","Model"]` instead of `"Make,Model"`. Moreover the option `groupField: ['name']` will be overwritten by (see [the lines](https://github.com/tonytomov/jqGrid/blob/master/js/grid.grouping.js#L393-L394)). I still don't understand why you not use the option `groupingView: {groupField: ["Make", "Model"], groupCollapse: true}`. You can change the options using `setGridParam` any time, but I don't understand why you could need call `groupingGroupBy` inside of `beforeRequest`? – Oleg Oct 07 '13 at 20:40
  • Moreover I don't understand why you set `beforeSend`, `complete` and `error` inside of `ajaxGridOptions`. Such settings will overwrite the main jqGrid code of `$.ajax`. – Oleg Oct 07 '13 at 20:42
  • The use of beforeSend, complete & error inside ajaxGridOptions is for displaying alternative loading animation, plus to let me know if the error occurred on the server-side scripts. Nothing to do with multilevel grouping. – fletchsod Oct 07 '13 at 21:13
  • As for groupingView: {groupField: ["Make", "Model", groupCollapse: true}. For one customer, the webpage will be loaded as multilevel grouping of Make & Model. For 2nd customer, there is no multilevel grouping. For 3rd customer, there will be multilevel grouping of StockDate & PurchasePrice. The problem I have is every customers have their preferences, so that's why I use their saved setting to teh database so I can customize the display jqGrid result based on what the customer wants. – fletchsod Oct 07 '13 at 21:16
  • Is there good example of using setGridParam?? I noticed few examples require using .trigger('reloadGrid') for it to work. The use of 'reloadGrid' can't be use in beforeRequest function or it go into infinite loop. – fletchsod Oct 07 '13 at 21:17
  • Look in [the answer](http://stackoverflow.com/a/9422170/315935) for example. In general you can just use something like `$(this).jqGrid("setGridParam", {grouping: true, groupingView: {groupField: ["Make", "Model"]}});` inside of `beforeRequest` instead of usage `groupingGroupBy`. – Oleg Oct 07 '13 at 21:34
  • Something not working right here. See Example #1 above, it works. But Example #2 failed with an error, so it not gonna work. So, I tried Example #3 and it doesn't show the multilevel grouping. But Example #3 will work if you enable the ".trigger('reloadGrid')" but it have a side effect, an infinite loop. So, what are your suggestion and what's my options here? Thanks... – fletchsod Oct 08 '13 at 13:58

1 Answers1

1

Example 2 have the following error: you use unneeded {...}. The code beforeRequest: function() {$('#test').jqGrid({'setGridParam', {...}});} should be replace with beforeRequest: function() {$(this).jqGrid('setGridParam', {...});}.

I still see no sense in usage of static groupField values. If you hold the data about groping on the server I would see more sense that the server return information about grouping preferences of the user as the part of server response. In the case you can use beforeProcessing callback to analyse the corresponding part of the server response and to set grouping and groupingView option of jqGrid.

UPDATED: One can fix the example 6 by additional calling of groupingSetup method after setting new groupingView options:

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

I prepared the corresponding demo. I use in the demo the JSON data in the following format

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

and the following 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");
}

So I get the grouping fields (["name", "amount"]) from the server response.

Oleg
  • 220,925
  • 34
  • 403
  • 798
  • I updated the script and still the same thing. Example #2, it doesn't show the multilevel grouping because .trigger('reloadGrid') is needed for it to work but by doing this, it go into infinite loop. Example #4, I used the beforeProcessing option but it still does the same thing as Example #2. I'm still back to square one. Have you tried it out to see if any options would work? Thanks. – fletchsod Oct 09 '13 at 18:39
  • Yes I hold the data about grouping on the server. I added Example #5 as it works for me. But it is a dump workaround. Do you have a better suggestion on that? – fletchsod Oct 09 '13 at 22:48
  • @fletchsod: I suppose that the problem can be the same like in the **UPDATED 2** part of [the answer](http://stackoverflow.com/a/13194985/315935) - you don't use `gridview: true`. You have to follow [limitations](http://www.trirand.com/jqgridwiki/doku.php?id=wiki:grouping#limitations) of grouping. Calling `trigger('reloadGrid');` is *not needed*. You can remove usage `blockInfiniteLoopCounter` too and just use `setGridParam`. I suppose that Example 2 and Example 4 will work after including of `gridview: true`. By the way it's the option which I use in *all* my grids. – Oleg Oct 10 '13 at 05:03
  • In Example #6 - I copied the script you made at that "the answer" webpage and tweaked it to include the "beforeProcessing" function plus changing rownumber to false. It doesn't show multilevel grouping upon loading. What could be the problem there in Example #6? Thanks. – fletchsod Oct 10 '13 at 17:53
  • @fletchsod: I updated my answer and included [the demo](http://www.ok-soft-gmbh.com/jqGrid/SetOnSelectDynamically1_.htm) which demonstrates how to fix the problem. – Oleg Oct 10 '13 at 18:40
  • @ Oleg : Oh nice! Thank you for the demo. It wouldn't have work if I left out the "groupingSetup". That's a nice script on using data.groupField. Impressive. I applied to my project and it works great! Thank you for your patience. :-) – fletchsod Oct 10 '13 at 23:03