0

I'm currently using jqgrid 5.0.2 I have a parent grid with a fixed width of 800 px, and a sub grid that is larger. What I need to do is display all of the columns of the subgrid, without requiring a horizontal scroll bar.

The columns initially displayed in the subgrid are only those that are within the width of the parent grid. Even when I set the width of the parent grid to something wider that should display the columns of the subgrid, the columns to the right of the width of the parent grid require use of a horizontal scroll bar.

In the example below, I've set the width of the parent grid to 1200 pixels. However, I still need to use the horizontal scroll bar of the subgrid to get to the columns that exceed the parent grid's width.

enter image description here

Here's the code I'm using:

var mainGrid = {
  "total": 1,
  "page": 1,
  "pageSize": 20,
  "records": 1,
  "rows": [{
    "siteId": 12516086,
    "siteName": "Detroit",
    "siteAddress": "1 Woodward",
    "siteCitySt": "Detroit, MI",
    "siteZip": "48205",
    "productCd": "ProductX",
    "productName": "Product X",
    "finishedSize": null,
    "estimatedPieceWeight": 0.125,
    "vdpTypeCode": null,
    "taHouseholds": 1071689,
    "taDistribution": 445139,
    "distribution": 445139,
    "avgCpm": 32.32084084084084084084084084084084084084,
    "investment": 19542.8,
    "coverage": 41.54
  }]
};

var subGrid = {
  "total": 1,
  "page": 1,
  "pageSize": 20,
  "records": 2,
  "rows": [{
    "mediaPlanId": 3003,
    "mbuHdrId": 4035986,
    "mbuDtlId": 10442611,
    "commonMbuId": 99731,
    "ggId": 1244425,
    "fkGeoProfileId": 15032061,
    "fkSite": 12516086,
    "wrapZoneId": 15049936,
    "wrapZone": "MI Detroit/ Highland Park/ Hamtramck",
    "productCd": "INS_SHARED",
    "productName": "Insert - Shared Mail",
    "wrapPagePosition": null,
    "finishedSize": null,
    "estimatedPieceWeight": 0.125,
    "vdpTypeCode": null,
    "geocode": "48205D1",
    "zip": "48205",
    "atz": "D1",
    "cityName": "DETROIT, MI",
    "households": 2088,
    "taHouseholds": 2088,
    "distribution": 2092,
    "cpm": 0,
    "investment": 0.0,
    "overallCoverage": 100.191570881226053639846743295019157088,
    "taCoverage": 100.191570881226053639846743295019157088,
    "distance": 0.62,
    "coverageDescDisplay": "Pcd",
    "coverageDesc": "Private Carrier Delivery",
    "ihDate": 1463371200000,
    "ihDay": "M/T",
    "pricingMarket": "MI DETROIT",
    "fkSdmId": 15075973,
    "sdmName": "MI Detroit",
    "fkVariableId": 7039,
    "primaryVariableName": "Candy & Chewing Gum",
    "variableContents": "INDEX",
    "variableValue": 63.52,
    "isSelected": true,
    "isActiveMbuCmn": true,
    "isActiveMbuHdr": true,
    "isActiveMbuDtl": true,
    "isUsedInCbx": true,
    "isBought": true,
    "var1Name": "Candy & Chewing Gum",
    "var1Contents": "INDEX",
    "var1Value": "64",
    "var2Name": "Toys, Games, and Hobbies",
    "var2Contents": "INDEX",
    "var2Value": "74",
    "var3Name": "Casual Dining: Olive Garden",
    "var3Contents": "INDEX",
    "var3Value": "83"
  }, {
    "mediaPlanId": 3003,
    "mbuHdrId": 4035988,
    "mbuDtlId": 10442613,
    "commonMbuId": 99732,
    "ggId": 1244426,
    "fkGeoProfileId": 22973059,
    "fkSite": 12516086,
    "wrapZoneId": 15049936,
    "wrapZone": "MI Detroit/ Highland Park/ Hamtramck",
    "productCd": "INS_SHARED",
    "productName": "Insert - Shared Mail",
    "wrapPagePosition": null,
    "finishedSize": null,
    "estimatedPieceWeight": 0.125,
    "vdpTypeCode": null,
    "geocode": "48205G1",
    "zip": "48205",
    "atz": "G1",
    "cityName": "DETROIT, MI",
    "households": 1156,
    "taHouseholds": 1156,
    "distribution": 1157,
    "cpm": 0,
    "investment": 0.0,
    "overallCoverage": 100.086505190311418685121107266435986159,
    "taCoverage": 100.086505190311418685121107266435986159,
    "distance": 0.74,
    "coverageDescDisplay": "Pcd",
    "coverageDesc": "Private Carrier Delivery",
    "ihDate": 1463371200000,
    "ihDay": "M/T",
    "pricingMarket": "MI DETROIT",
    "fkSdmId": 15075973,
    "sdmName": "MI Detroit",
    "fkVariableId": 7039,
    "primaryVariableName": "Candy & Chewing Gum",
    "variableContents": "INDEX",
    "variableValue": 68.06,
    "isSelected": false,
    "isActiveMbuCmn": true,
    "isActiveMbuHdr": true,
    "isActiveMbuDtl": true,
    "isUsedInCbx": true,
    "isBought": false,
    "var1Name": "Candy & Chewing Gum",
    "var1Contents": "INDEX",
    "var1Value": "68",
    "var2Name": "Toys, Games, and Hobbies",
    "var2Contents": "INDEX",
    "var2Value": "78",
    "var3Name": "Casual Dining: Olive Garden",
    "var3Contents": "INDEX",
    "var3Value": "91"
  }]
};

$(document).ready(function() {
  $("#jqGrid").jqGrid({
    datatype: function(postdata) {

      $('#' + 'load_' + 'jqGrid').show();

      var json = mainGrid;

      for (var i = 0; i < json.rows.length; i++) {
        json.rows[i].id = $.jgrid.randId();
        json.rows[i].siteNameDisp = json.rows[i].siteName + ' - ' +
          json.rows[i].siteAddress + ', ' +
          json.rows[i].siteCitySt + ', ' +
          json.rows[i].siteZip;
      }

      var thegrid = $('#jqGrid')[0];
      thegrid.addJSONData(json);

      $('#' + 'load_' + 'jqGrid').hide();
    },
    page: 1,
    colModel: [{
      label: 'ID',
      name: 'id',
      width: 50,
      hidden: true,
      key: true,
      editable: true,
      sortable: false,
      editrules: {
        edithidden: true
      }
    }, {
      label: 'Site Id',
      name: 'siteId',
      width: 100,
      sortable: false,
      editable: true,
      hidden: true,
      editrules: {
        edithidden: true
      }
    }, {
      label: 'Site',
      name: 'siteNameDisp',
      width: 250,
      sortable: false
    }, {
      label: 'Trade Area Households',
      name: 'taHouseholds',
      width: 100,
      sortable: false,
      formatter: 'number',
      formatoptions: {
        thousandsSeparator: ",",
        decimalPlaces: 0
      },
      align: 'right'
    }, {
      label: 'Trade Area Distribution',
      name: 'taDistribution',
      width: 85,
      sortable: false,
      formatter: 'number',
      formatoptions: {
        thousandsSeparator: ",",
        decimalPlaces: 0
      },
      align: 'right'
    }, {
      label: 'Total Distribution',
      name: 'distribution',
      width: 85,
      sortable: false,
      formatter: 'number',
      formatoptions: {
        thousandsSeparator: ",",
        decimalPlaces: 0
      },
      align: 'right'
    }, {
      label: 'CPM',
      name: 'avgCpm',
      width: 50,
      sortable: false,
      formatter: 'currency',
      formatoptions: {
        decimalSeparator: ".",
        thousandsSeparator: ",",
        decimalPlaces: 2,
        prefix: "$ "
      },
      align: 'right'
    }, {
      label: 'Investment',
      name: 'investment',
      width: 75,
      sortable: false,
      formatter: 'currency',
      formatoptions: {
        decimalSeparator: ".",
        thousandsSeparator: ",",
        decimalPlaces: 2,
        prefix: "$ "
      },
      align: 'right'
    }, {
      label: 'Coverage %',
      name: 'coverage',
      width: 70,
      sortable: false,
      formatter: 'currency',
      formatoptions: {
        decimalSeparator: ".",
        thousandsSeparator: ",",
        decimalPlaces: 2,
        suffix: " %"
      },
      align: 'right'
    }, {
      label: 'Product',
      name: 'productCd',
      width: 150,
      sortable: false,
      editable: true,
      hidden: true,
      editrules: {
        edithidden: true
      }
    }],
    viewrecords: true,
    width: 1200,
    shrinkToFit: false,
    //height: '100%',
    rowNum: 20,
    pager: "#jqGridPager",
    subGrid: true,
    subGridRowExpanded: function(subgrid_id, parentRowId) {
      var grid = $("#jqGrid");
      var row = grid.getRowData(parentRowId);
      showDetail(subgrid_id, parentRowId);
    }
  });
});

function showDetail(subgrid_id, parentRowId) {
  var lastSelection;

  var parentGridId = 'jqGrid';

  var grid = $('#' + parentGridId);
  var row = grid.getRowData(parentRowId);
  var siteId = row.siteId;
  var productCode = row.productCd;

  var subgrid_table_id = subgrid_id + "_table";
  var subgrid_pager_id = subgrid_id + "_pager";

  $("#" + subgrid_id).html("<table id=\'" + subgrid_table_id + "' class='scroll'></table>" +
    "<div id=\'" + subgrid_pager_id + "\'></div>");

  $("#" + subgrid_table_id).jqGrid({

    datatype: function(postdata) {
      $('#' + 'load_' + subgrid_table_id).show();

      var json = subGrid;

      for (var i = 0; i < json.rows.length; i++) {
        json.rows[i].taDistribution = json.rows[i].distribution;
        json.rows[i].parentGridId = parentGridId;
        json.rows[i].parentRowId = parentRowId;
      }

      var thegrid = $("#" + subgrid_table_id)[0];
      thegrid.addJSONData(json);
      $('#' + 'load_' + subgrid_table_id).hide();
    },

    editurl: 'clientArray',
    page: 1,

    colModel: [{
        label: 'Site ID',
        name: 'siteId',
        width: 75,
        //key: true,  // The key field must be visible in order for the row to go into edit mode.
        sortable: false,
        editable: true,
        hidden: true,
        editrules: {
          edithidden: true
        }
      }, {
        label: 'Common MBU ID',
        name: 'commonMbuId',
        width: 75,
        //key: true,  // The key field must be visible in order for the row to go into edit mode.
        sortable: false,
        editable: true,
        hidden: true,
        editrules: {
          edithidden: true
        }
      }, {
        label: 'Parent Grid ID',
        name: 'parentGridId',
        width: 75,
        hidden: true
      },

      {
        label: 'Parent Row ID',
        name: 'parentRowId',
        width: 75,
        hidden: true
      }, {
        label: 'Geography',
        name: 'geocode',
        width: 90,
        sortable: true,
        key: true
      }, {
        label: 'City, State',
        name: 'cityName',
        width: 115,
        sortable: true
      }, {
        label: 'TA HHs',
        name: 'taHouseholds',
        width: 50,
        sortable: true,
        formatter: 'number',
        formatoptions: {
          thousandsSeparator: ",",
          decimalPlaces: 0
        },
        align: 'right'
      }, {
        label: 'Distr Qty',
        name: 'distribution',
        width: 50,
        sortable: true,
        formatter: 'number',
        formatoptions: {
          thousandsSeparator: ",",
          decimalPlaces: 0
        },
        align: 'right'
      }, {
        label: 'TA Distr',
        name: 'taDistribution',
        width: 50,
        sortable: false,
        hidden: true,
        formatter: 'number',
        formatoptions: {
          thousandsSeparator: ",",
          decimalPlaces: 0
        },
        align: 'right'
      },

      {
        label: 'CPM',
        name: 'cpm',
        width: 50,
        sortable: true,
        formatter: 'currency',
        formatoptions: {
          decimalSeparator: ".",
          thousandsSeparator: ",",
          decimalPlaces: 2,
          prefix: ""
        },
        align: 'right'
      },

      {
        label: 'Investment',
        name: 'investment',
        width: 90,
        sortable: true,
        formatter: 'currency',
        formatoptions: {
          decimalSeparator: ".",
          thousandsSeparator: ",",
          decimalPlaces: 2,
          prefix: "$ "
        },
        align: 'right'
      },

      {
        label: 'Coverage %',
        name: 'taCoverage',
        width: 85,
        sortable: true,
        formatter: 'currency',
        formatoptions: {
          decimalSeparator: ".",
          thousandsSeparator: ",",
          decimalPlaces: 2,
          suffix: " %"
        },
        align: 'right'
      },

      {
        label: 'Distance',
        name: 'distance',
        width: 75,
        sortable: true,
        formatter: 'number',
        formatoptions: {
          thousandsSeparator: ",",
          decimalPlaces: 2
        },
        align: 'right'
      },

      {
        label: 'Coverage Description',
        name: 'coverageDescDisplay',
        width: 90,
        sortable: true
      },

      {
        label: 'IH Date',
        name: 'ihDate',
        width: 60,
        sortable: true,
        //formatter: dateFormatter,
        align: 'center'
      },

      {
        label: 'IH Day',
        name: 'ihDay',
        width: 60,
        sortable: true,
        align: 'center'
      },

      {
        label: 'Pricing Market',
        name: 'pricingMarket',
        width: 115,
        sortable: true
      }, {
        label: ' ',
        name: 'variableValue',
        width: 90,
        sortable: true,
        hidden: false,
        align: 'right'
      },

      // Variable 1
      {
        label: ' ',
        name: 'var1Value',
        width: 90,
        sortable: true,
        hidden: false,
        align: 'right'
      },

      // Variable 2
      {
        label: ' ',
        name: 'var2Value',
        width: 90,
        sortable: true,
        hidden: false,
        align: 'right'
      },

      // Variable 3
      {
        label: ' ',
        name: 'var3Value',
        width: 90,
        sortable: true,
        hidden: false,
        align: 'right'
      }

    ],
    viewrecords: true,
    height: '100%',
    shrinkToFit: false,
    //width: 1400,
    autowidth: true,
    rowNum: 20,
    pager: "#" + subgrid_pager_id
  });

}

And here is a link to the code running in jsFiddle:

https://jsfiddle.net/msobczak/3yar2vr1/8/

UPDATE

I revised the jsFiddle to include the following statements to resize one of the columns in the parent grid, but nothing changes:

grid.jqGrid('setColProp','coverage',{width:diff});
grid.jqGrid('setColProp','coverage',{widthOrg:diff});

https://jsfiddle.net/msobczak/3yar2vr1/9/

Michael Sobczak
  • 1,045
  • 1
  • 24
  • 45

1 Answers1

0

Subgrid will be created inside of the cells of the main grid. Thus the width of the main grid should be increased to solve the problem. I suggest you to increase the width value of the last visible column to fill the grid. You can use align: 'left' or to use classes to change the position of the text in the column. You should change the position of the corresponding column header (using labelAlign: "left" in free jqGrid and usage of setLabel in other jqGrid forks). You will get practically the same view of grid/subgrid like you asked for.

Oleg
  • 220,925
  • 34
  • 403
  • 798
  • I was thinking something along those lines. Instead of increasing the width of the last column, I'd add a "padding column" and change its width when the subgrid is shown. – Michael Sobczak Aug 29 '16 at 19:13
  • @MichaelSobczak: It's mostly the same, but it sounds even a little better as my suggestion. In any way the total width of the main grid have to be the same or larger the width of the subgrid. Only in the case the subgrid will be seen without horizontal scrollbar. – Oleg Aug 29 '16 at 19:15
  • I tried resizing the column, but the overall size of the parent grid stays the same. Is there another step I need to do after changing the column width? – Michael Sobczak Aug 29 '16 at 21:15
  • 1
    @MichaelSobczak: You try to implement some custom scenario. The main grid and the child grid are two relatively independent grids. If you want some kind of resizing of one groin on resizing of the second one then you have to do this explicitly. See [the answer](http://stackoverflow.com/a/14265456/315935). It seems to me that resizing in not a part of your current question. the main goal of stackoverflow is sharing common questions with other users. Because of that one should not mix multiple questions inside of one question: such questions can be bad indexed and bad fount by other visitors. – Oleg Aug 29 '16 at 21:25
  • Yes, I thought twice about adding onto this post. You've answered so many questions on this forum, I thought this would be a quick referral answer. Actually, I was thinking about implementing what you demoed in this post: http://stackoverflow.com/questions/20012365/how-to-adjust-the-column-width-of-jqgrid-after-the-data-is-loaded – Michael Sobczak Aug 30 '16 at 12:34
  • I posted a new question that relates to this one here: http://stackoverflow.com/questions/39254753/jqgrid-scrollbars-display-after-changing-parent-grid-column-size – Michael Sobczak Sep 01 '16 at 11:32
  • @MichaelSobczak: Sorry, but I can't help you with Guriddo jqGrid. By the way the method `setColWidth` is builtin method in [free jqGrid](https://github.com/free-jqgrid/jqGrid), which I develop. Do you tried whether the same problem exist in free jqGrid too? Moreover, you use `datatype` defined as function. It's very bad way. The way was introduced in very old version of jqGrid. The later versions do much more after/before loading the grid. The implementation `datatype` defined as function, which you use now is incorrect (or not full correct) for current versions of jqGrid. – Oleg Sep 01 '16 at 11:36
  • Using datatype as function is required for what I'm doing. I'm using jqgrid within Salesforce, which requires me to make asynchronous calls to the service via a proxy. I haven't seen a way around that. What specifically is wrong with how I use datatype as function in the current version of jqgrid? What I'm doing still works fine in 5.1.1 – Michael Sobczak Sep 01 '16 at 16:04
  • @MichaelSobczak: I don't know your exact environment, but one can use Force.com REST API for example. See [here](https://developer.salesforce.com/blogs/developer-relations/2015/08/creating-jquery-application-using-rest-api.html). One can set `Authorization` header, which starts with `"Bearer "` prefix by usage `ajaxGridOptions` option or by usage `loadBeforeSend` callback. See [the answer](http://stackoverflow.com/a/5706690/315935) for an example. – Oleg Sep 01 '16 at 16:49
  • @MichaelSobczak: Alternatively one do can use `datatype` defined as function, but you have to change the implementation. See [the part](https://github.com/free-jqgrid/jqGrid/blob/v4.13.4/js/grid.base.js#L4300-L4321). Your current code breaks functionality of jqGrid because many mandatory callbacks be not called (like `loadComplete`) and events will be not triggered (like `jqGridLoadComplete`, `jqGridAfterLoadComplete` and other). I recommend you don't use `datatype` defined as function neither with free jqGrid not with Guriddo and any old jqGrid (like 4.6 for example). – Oleg Sep 01 '16 at 16:53
  • Within my Salesforce page, I need to call out to a service which resides outside of Salesforce. The external service runs in a jboss Fuse container. To avoid cross-domain scripting issues, I need to utilize Salesforce JavaScript remoting. This involves invoking a method in a Salesforce Apex class, which does an Http callout to the Fuse service. Most examples I see with jqgrid assume that the service being called is in the same domain as the web page where jqgrid is running. That is not true in my case. – Michael Sobczak Sep 01 '16 at 17:28
  • @MichaelSobczak: One can use `datatype: "jsonp"`. See [the demo](http://www.ok-soft-gmbh.com/jqGrid/user781065_jsonp.htm) from [the answer](http://stackoverflow.com/a/9588051/315935). If the server, which you need to access, supports CORS then you need use the corresponding jQuery.ajax option (`ajaxGridOptions: { xhrFields: { withCredentials: true } })` for example) or to set `Access-Control-Allow-Origin`. I recommend you to create the test, where you access the data from the server via jQuery.ajax, then one can easy use jqGrid too. – Oleg Sep 01 '16 at 17:43
  • Unfortunately, opening up CORS in our production SF environment isn't going to happen. – Michael Sobczak Sep 01 '16 at 19:36
  • @MichaelSobczak: Sorry, CORS means not only `Access-Control-Allow-Origin: *` and no authentication. One can forward credentials via Ajax call. We can't discuss all details here. Moreover the discussion is for from the main thread (your original question). I just gets you my personal recommendations. – Oleg Sep 01 '16 at 19:50