jQWidgets Forums

jQuery UI Widgets Forums Grid Any way to force a grouped grid to redraw when used inside tabs?

Tagged: 

This topic contains 8 replies, has 2 voices, and was last updated by  slodge 12 years, 7 months ago.

Viewing 9 posts - 1 through 9 (of 9 total)
  • Author

  • slodge
    Member

    Hi

    I’m currently seeing this kind of “white group” effect when using multiple grids inside a tab control:

    The code to reproduce this is included below. If I remove the tabs, then everything displays normally.

    Can you suggest any way to resolve this – e,g, is there any way to request a redraw when I switch between tabs?

    Thanks

    Stuart

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <title id='Description'>This example tries to work out how to get grouped grids working inside tabs.</title>
    <link rel="stylesheet" href="/Content/jqx/jqx.base.css" type="text/css" />
    <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
    <script src="/Scripts/jqx/jqx-all.js" type="text/javascript"></script>
    <script type="text/javascript" src="/Scripts/jqx/globalization/jquery.global.js"></script>
    <script type="text/javascript">
    $(document).ready(function () {
    $('#tabs').jqxTabs({ width: '90%', height: 200, position: 'top' });
    var data = generatedata(100);
    var source =
    {
    localdata: data,
    datatype: "array"
    };
    var dataAdapter = new $.jqx.dataAdapter(source);
    $("#samplegrid1").jqxGrid(
    {
    width: 670,
    source: dataAdapter,
    showfilterrow: false,
    filterable: false,
    groupable:true,
    groups: ['productname'],
    selectionmode: 'singlecell',
    columns: [
    { text: 'Name', columntype: 'textbox', datafield: 'name', width: 120 },
    { text: 'Product', filtertype: 'checkedlist', datafield: 'productname', width: 160 },
    { text: 'Available', datafield: 'available', columntype: 'checkbox', filtertype: 'bool', width: 67 },
    { text: 'Ship Date', datafield: 'date', filtertype: 'date', width: 180, cellsalign: 'right', cellsformat: 'd' },
    { text: 'Qty.', datafield: 'quantity', filtertype: 'number', width: 50, cellsalign: 'right' },
    { text: 'Price', datafield: 'price', filtertype: 'number', cellsalign: 'right', cellsformat: 'c2' }
    ]
    });
    $("#samplegrid2").jqxGrid(
    {
    width: 670,
    source: dataAdapter,
    showfilterrow: false,
    filterable: false,
    groupable:true,
    groups: ['available'],
    selectionmode: 'singlecell',
    columns: [
    { text: 'Name', columntype: 'textbox', datafield: 'name', width: 120 },
    { text: 'Product', filtertype: 'checkedlist', datafield: 'productname', width: 160 },
    { text: 'Available', datafield: 'available', columntype: 'checkbox', filtertype: 'bool', width: 67 },
    { text: 'Ship Date', datafield: 'date', filtertype: 'date', width: 180, cellsalign: 'right', cellsformat: 'd' },
    { text: 'Qty.', datafield: 'quantity', filtertype: 'number', width: 50, cellsalign: 'right' },
    { text: 'Price', datafield: 'price', filtertype: 'number', cellsalign: 'right', cellsformat: 'c2' }
    ]
    });
    });
    function generatedata(rowscount) {
    // prepare the data
    var data = new Array();
    if (rowscount == undefined) rowscount = 100;
    var firstNames =
    [
    "Andrew", "Nancy", "Shelley", "Regina", "Yoshi", "Antoni", "Mayumi", "Ian", "Peter", "Lars", "Petra", "Martin", "Sven", "Elio", "Beate", "Cheryl", "Michael", "Guylene"
    ];
    var lastNames =
    [
    "Fuller", "Davolio", "Burke", "Murphy", "Nagase", "Saavedra", "Ohno", "Devling", "Wilson", "Peterson", "Winkler", "Bein", "Petersen", "Rossi", "Vileid", "Saylor", "Bjorn", "Nodier"
    ];
    var productNames =
    [
    "Black Tea", "Green Tea", "Caffe Espresso", "Doubleshot Espresso", "Caffe Latte", "White Chocolate Mocha", "Caramel Latte", "Caffe Americano", "Cappuccino", "Espresso Truffle", "Espresso con Panna", "Peppermint Mocha Twist"
    ];
    var priceValues =
    [
    "2.25", "1.5", "3.0", "3.3", "4.5", "3.6", "3.8", "2.5", "5.0", "1.75", "3.25", "4.0"
    ];
    for (var i = 0; i < rowscount; i++) {
    var row = {};
    var productindex = Math.floor(Math.random() * productNames.length);
    var price = parseFloat(priceValues[productindex]);
    var quantity = 1 + Math.round(Math.random() * 10);
    row["id"] = i;
    row["available"] = productindex % 2 == 0;
    row["firstname"] = firstNames[Math.floor(Math.random() * firstNames.length)];
    row["lastname"] = lastNames[Math.floor(Math.random() * lastNames.length)];
    row["name"] = row["firstname"] + " " + row["lastname"];
    row["productname"] = productNames[productindex];
    row["price"] = price;
    row["quantity"] = quantity;
    row["total"] = price * quantity;
    var date = new Date();
    date.setFullYear(2012, Math.floor(Math.random() * 11), Math.floor(Math.random() * 27));
    date.setHours(0, 0, 0, 0);
    row["date"] = date;
    data[i] = row;
    }
    return data;
    }
    </script>
    </head>
    <body class='default'>
    <div id="tabs">
    <ul>
    <li>by name</li>
    <li>by available</li>
    </ul>
    <div id="samplegrid1">
    </div>
    <div id="samplegrid2">
    </div>
    </div>
    </body>
    </html>

    Peter Stoev
    Keymaster

    Hi slodge,

    The Grid is not initialized correctly in this code. See this sample for details how to use jqxGrid or any other widget within jqxTabs: http://www.jqwidgets.com/jquery-widgets-demo/demos/jqxtabs/integration.htm?classic

    Best Regards,
    Peter Stoev

    jQWidgets Team
    http://www.jqwidgets.com


    slodge
    Member

    Thanks

    If I change the code to use this then I still see the same problem – only now it’s on the first of the two tabs (when I switch back)

    Stuart

                var init1 = function() {
    $("#samplegrid1").jqxGrid(
    {
    width: 670,
    source: dataAdapter,
    showfilterrow: false,
    filterable: false,
    groupable: true,
    groups: ['productname'],
    selectionmode: 'singlecell',
    columns: [
    { text: 'Name', columntype: 'textbox', datafield: 'name', width: 120 },
    { text: 'Product', filtertype: 'checkedlist', datafield: 'productname', width: 160 },
    { text: 'Available', datafield: 'available', columntype: 'checkbox', filtertype: 'bool', width: 67 },
    { text: 'Ship Date', datafield: 'date', filtertype: 'date', width: 180, cellsalign: 'right', cellsformat: 'd' },
    { text: 'Qty.', datafield: 'quantity', filtertype: 'number', width: 50, cellsalign: 'right' },
    { text: 'Price', datafield: 'price', filtertype: 'number', cellsalign: 'right', cellsformat: 'c2' }
    ]
    });
    };
    var init2 = function() {
    $("#samplegrid2").jqxGrid(
    {
    width: 670,
    source: dataAdapter,
    showfilterrow: false,
    filterable: false,
    groupable: true,
    groups: ['available'],
    selectionmode: 'singlecell',
    columns: [
    { text: 'Name', columntype: 'textbox', datafield: 'name', width: 120 },
    { text: 'Product', filtertype: 'checkedlist', datafield: 'productname', width: 160 },
    { text: 'Available', datafield: 'available', columntype: 'checkbox', filtertype: 'bool', width: 67 },
    { text: 'Ship Date', datafield: 'date', filtertype: 'date', width: 180, cellsalign: 'right', cellsformat: 'd' },
    { text: 'Qty.', datafield: 'quantity', filtertype: 'number', width: 50, cellsalign: 'right' },
    { text: 'Price', datafield: 'price', filtertype: 'number', cellsalign: 'right', cellsformat: 'c2' }
    ]
    });
    };
    var initTabsPlease = function(which) {
    switch (which) {
    case 0:
    init1();
    break;
    case 1:
    init2();
    break;
    }
    };
    $('#tabs').jqxTabs({ width: '90%', height: 200, position: 'top', initTabContent: initTabsPlease });
    });

    slodge
    Member

    (If it helps) I’m testing in Chrome Canary and IE9 (x64) and seeing the same thing in both


    Peter Stoev
    Keymaster

    Hi slodge,

    This code renders the Grids correctly on my side:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <title id='Description'>This example tries to work out how to get grouped grids working inside tabs.</title>
    <link rel="stylesheet" href="../../jqwidgets/styles/jqx.base.css" type="text/css" />
    <script type="text/javascript" src="../../scripts/jquery-1.8.1.min.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxcore.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxdata.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxbuttons.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxscrollbar.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxmenu.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxgrid.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxgrid.grouping.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxgrid.selection.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxgrid.filter.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxlistbox.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxdropdownlist.js"></script>
    <script type="text/javascript" src="../../jqwidgets/jqxtabs.js"></script>
    <script type="text/javascript" src="../../scripts/gettheme.js"></script>
    <script type="text/javascript">
    $(document).ready(function () {
    var init1 = function () {
    var data = generatedata(100);
    var source =
    {
    localdata: data,
    datatype: "array"
    };
    var dataAdapter = new $.jqx.dataAdapter(source);
    $("#samplegrid1").jqxGrid(
    {
    width: 670,
    source: dataAdapter,
    showfilterrow: false,
    filterable: false,
    groupable: true,
    groups: ['productname'],
    selectionmode: 'singlecell',
    columns: [
    { text: 'Name', columntype: 'textbox', datafield: 'name', width: 120 },
    { text: 'Product', filtertype: 'checkedlist', datafield: 'productname', width: 160 },
    { text: 'Available', datafield: 'available', columntype: 'checkbox', filtertype: 'bool', width: 67 },
    { text: 'Ship Date', datafield: 'date', filtertype: 'date', width: 180, cellsalign: 'right', cellsformat: 'd' },
    { text: 'Qty.', datafield: 'quantity', filtertype: 'number', width: 50, cellsalign: 'right' },
    { text: 'Price', datafield: 'price', filtertype: 'number', cellsalign: 'right', cellsformat: 'c2' }
    ]
    });
    };
    var init2 = function () {
    var data = generatedata(100);
    var source =
    {
    localdata: data,
    datatype: "array"
    };
    var dataAdapter = new $.jqx.dataAdapter(source);
    $("#samplegrid2").jqxGrid(
    {
    width: 670,
    source: dataAdapter,
    showfilterrow: false,
    filterable: false,
    groupable: true,
    groups: ['available'],
    selectionmode: 'singlecell',
    columns: [
    { text: 'Name', columntype: 'textbox', datafield: 'name', width: 120 },
    { text: 'Product', filtertype: 'checkedlist', datafield: 'productname', width: 160 },
    { text: 'Available', datafield: 'available', columntype: 'checkbox', filtertype: 'bool', width: 67 },
    { text: 'Ship Date', datafield: 'date', filtertype: 'date', width: 180, cellsalign: 'right', cellsformat: 'd' },
    { text: 'Qty.', datafield: 'quantity', filtertype: 'number', width: 50, cellsalign: 'right' },
    { text: 'Price', datafield: 'price', filtertype: 'number', cellsalign: 'right', cellsformat: 'c2' }
    ]
    });
    };
    var initTabsPlease = function (which) {
    switch (which) {
    case 0:
    init1();
    break;
    case 1:
    init2();
    break;
    }
    };
    $('#tabs').jqxTabs({ width: '90%', height: 200, position: 'top', initTabContent: initTabsPlease });
    });
    function generatedata(rowscount) {
    // prepare the data
    var data = new Array();
    if (rowscount == undefined) rowscount = 100;
    var firstNames =
    [
    "Andrew", "Nancy", "Shelley", "Regina", "Yoshi", "Antoni", "Mayumi", "Ian", "Peter", "Lars", "Petra", "Martin", "Sven", "Elio", "Beate", "Cheryl", "Michael", "Guylene"
    ];
    var lastNames =
    [
    "Fuller", "Davolio", "Burke", "Murphy", "Nagase", "Saavedra", "Ohno", "Devling", "Wilson", "Peterson", "Winkler", "Bein", "Petersen", "Rossi", "Vileid", "Saylor", "Bjorn", "Nodier"
    ];
    var productNames =
    [
    "Black Tea", "Green Tea", "Caffe Espresso", "Doubleshot Espresso", "Caffe Latte", "White Chocolate Mocha", "Caramel Latte", "Caffe Americano", "Cappuccino", "Espresso Truffle", "Espresso con Panna", "Peppermint Mocha Twist"
    ];
    var priceValues =
    [
    "2.25", "1.5", "3.0", "3.3", "4.5", "3.6", "3.8", "2.5", "5.0", "1.75", "3.25", "4.0"
    ];
    for (var i = 0; i < rowscount; i++) {
    var row = {};
    var productindex = Math.floor(Math.random() * productNames.length);
    var price = parseFloat(priceValues[productindex]);
    var quantity = 1 + Math.round(Math.random() * 10);
    row["id"] = i;
    row["available"] = productindex % 2 == 0;
    row["firstname"] = firstNames[Math.floor(Math.random() * firstNames.length)];
    row["lastname"] = lastNames[Math.floor(Math.random() * lastNames.length)];
    row["name"] = row["firstname"] + " " + row["lastname"];
    row["productname"] = productNames[productindex];
    row["price"] = price;
    row["quantity"] = quantity;
    row["total"] = price * quantity;
    var date = new Date();
    date.setFullYear(2012, Math.floor(Math.random() * 11), Math.floor(Math.random() * 27));
    date.setHours(0, 0, 0, 0);
    row["date"] = date;
    data[i] = row;
    }
    return data;
    }
    </script>
    </head>
    <body class='default'>
    <div id="tabs">
    <ul>
    <li>by name</li>
    <li>by available</li>
    </ul>
    <div id="samplegrid1">
    </div>
    <div id="samplegrid2">
    </div>
    </div>
    </body>
    </html>

    Could you try it with jQWidgets 2.4.2? If it does not work, let me know what’s your browser and the browser’s version.

    The result of my code is:

    Best Regards,
    Peter Stoev

    jQWidgets Team
    http://www.jqwidgets.com


    slodge
    Member

    Aaaaahhhhh

    So the problem in the code I sent was in the shared dataAdapter as well as in the init?

    🙂

    Thanks for your help – I’m still trying to work out how the objects all work together

    Stuart


    slodge
    Member

    Hi Again

    Unfortunately this problem is still dogging me.

    What I’m seeing is that if a Grid update occurs while a tab is not visible, then that grid’s redraw is broken.

    I’ve worked around this a bit – especially by trying to avoid updates when not visible, but async data sources are causing updates :/

    The sample code below illustrates the problem. To run it:

    1. Start the page – switch back and forth between tabs – everything works well
    2. Use one of the buttons at the top of the page to request dataAdapter.databind() on the tab which isn’t visible

    I’m still wondering if there’s any kind of refresh/redraw\repaint command I can use to work around this?

    Stuart

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <title id='Description'>This example tries to work out how to get grouped grids working inside tabs.</title>
    <link rel="stylesheet" href="/Content/jqx/jqx.base.css" type="text/css" />
    <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
    <script src="/Scripts/jqx/jqx-all.js" type="text/javascript"></script>
    <script type="text/javascript" src="/Scripts/jqx/globalization/jquery.global.js"></script>
    <script type="text/javascript">
    $(document).ready(function () {
    var data = generatedata(100);
    var source =
    {
    localdata: data,
    datatype: "array"
    };
    var dataAdapter = new $.jqx.dataAdapter(source);
    $('#updateFirst').click(function () {
    dataAdapter.dataBind();
    });
    var init1 = function () {
    $("#samplegrid1").jqxGrid(
    {
    width: 670,
    source: dataAdapter,
    showfilterrow: false,
    filterable: false,
    groupable: true,
    groups: ['productname'],
    selectionmode: 'singlecell',
    columns: [
    { text: 'Name', columntype: 'textbox', datafield: 'name', width: 120 },
    { text: 'Product', filtertype: 'checkedlist', datafield: 'productname', width: 160 },
    { text: 'Available', datafield: 'available', columntype: 'checkbox', filtertype: 'bool', width: 67 },
    { text: 'Ship Date', datafield: 'date', filtertype: 'date', width: 180, cellsalign: 'right', cellsformat: 'd' },
    { text: 'Qty.', datafield: 'quantity', filtertype: 'number', width: 50, cellsalign: 'right' },
    { text: 'Price', datafield: 'price', filtertype: 'number', cellsalign: 'right', cellsformat: 'c2' }
    ]
    });
    };
    var data2 = generatedata(100);
    var source2 =
    {
    localdata: data2,
    datatype: "array"
    };
    var dataAdapter2 = new $.jqx.dataAdapter(source2);
    $('#updateSecond').click(function() {
    dataAdapter2.dataBind();
    });
    var init2 = function () {
    $("#samplegrid2").jqxGrid(
    {
    width: 670,
    source: dataAdapter2,
    showfilterrow: false,
    filterable: false,
    groupable: true,
    groups: ['available'],
    selectionmode: 'singlecell',
    columns: [
    { text: 'Name', columntype: 'textbox', datafield: 'name', width: 120 },
    { text: 'Product', filtertype: 'checkedlist', datafield: 'productname', width: 160 },
    { text: 'Available', datafield: 'available', columntype: 'checkbox', filtertype: 'bool', width: 67 },
    { text: 'Ship Date', datafield: 'date', filtertype: 'date', width: 180, cellsalign: 'right', cellsformat: 'd' },
    { text: 'Qty.', datafield: 'quantity', filtertype: 'number', width: 50, cellsalign: 'right' },
    { text: 'Price', datafield: 'price', filtertype: 'number', cellsalign: 'right', cellsformat: 'c2' }
    ]
    });
    };
    var initTabsPlease = function (which) {
    switch (which) {
    case 0:
    init1();
    break;
    case 1:
    init2();
    break;
    }
    };
    $('#tabs').jqxTabs({ width: '90%', height: 200, position: 'top', initTabContent: initTabsPlease });
    });
    function generatedata(rowscount) {
    // prepare the data
    var data = new Array();
    if (rowscount == undefined) rowscount = 100;
    var firstNames =
    [
    "Andrew", "Nancy", "Shelley", "Regina", "Yoshi", "Antoni", "Mayumi", "Ian", "Peter", "Lars", "Petra", "Martin", "Sven", "Elio", "Beate", "Cheryl", "Michael", "Guylene"
    ];
    var lastNames =
    [
    "Fuller", "Davolio", "Burke", "Murphy", "Nagase", "Saavedra", "Ohno", "Devling", "Wilson", "Peterson", "Winkler", "Bein", "Petersen", "Rossi", "Vileid", "Saylor", "Bjorn", "Nodier"
    ];
    var productNames =
    [
    "Black Tea", "Green Tea", "Caffe Espresso", "Doubleshot Espresso", "Caffe Latte", "White Chocolate Mocha", "Caramel Latte", "Caffe Americano", "Cappuccino", "Espresso Truffle", "Espresso con Panna", "Peppermint Mocha Twist"
    ];
    var priceValues =
    [
    "2.25", "1.5", "3.0", "3.3", "4.5", "3.6", "3.8", "2.5", "5.0", "1.75", "3.25", "4.0"
    ];
    for (var i = 0; i < rowscount; i++) {
    var row = {};
    var productindex = Math.floor(Math.random() * productNames.length);
    var price = parseFloat(priceValues[productindex]);
    var quantity = 1 + Math.round(Math.random() * 10);
    row["id"] = i;
    row["available"] = productindex % 2 == 0;
    row["firstname"] = firstNames[Math.floor(Math.random() * firstNames.length)];
    row["lastname"] = lastNames[Math.floor(Math.random() * lastNames.length)];
    row["name"] = row["firstname"] + " " + row["lastname"];
    row["productname"] = productNames[productindex];
    row["price"] = price;
    row["quantity"] = quantity;
    row["total"] = price * quantity;
    var date = new Date();
    date.setFullYear(2012, Math.floor(Math.random() * 11), Math.floor(Math.random() * 27));
    date.setHours(0, 0, 0, 0);
    row["date"] = date;
    data[i] = row;
    }
    return data;
    }
    </script>
    </head>
    <body class='default'>
    <div>
    <button title="Update First" value="Update First" id="updateFirst">Update First</button>
    <button title="Update Second" value="Update Second" id="updateSecond">Update Second</button>
    </div>
    <div id="tabs">
    <ul>
    <li>by name</li>
    <li>by available</li>
    </ul>
    <div id="samplegrid1">
    </div>
    <div id="samplegrid2">
    </div>
    </div>
    </body>
    </html>

    Peter Stoev
    Keymaster

    Hi Stuart,

    A redraw must occur only when the tab is selected. Otherwise, the Grid’s layout will use incorrect values for width and height – 0 for DIV tags with display: none. If you want to explicitly refresh the Grid, use its ‘render’ method.

    Best Regards,
    Peter Stoev

    jQWidgets Team
    http://www.jqwidgets.com


    slodge
    Member

    Thanks

    A small section like:

    $(‘#tabs’).bind(‘selected’, function (event) {
    var selectedTab = event.args.item;
    if (selectedTab == 0) {
    $(“#samplegrid1”).jqxGrid(‘render’);
    } else {
    $(“#samplegrid2”).jqxGrid(‘render’);
    }
    });

    Seems to solve my problem even when the async data in the real app

    Thanks 🙂

    Stuart

Viewing 9 posts - 1 through 9 (of 9 total)

You must be logged in to reply to this topic.