The grid does not render correctly unless the containing element is visible at initialization time

4 posts, 1 answers
  1. Ben
    Ben avatar
    2 posts
    Member since:
    Jul 2012

    Posted 20 Aug 2012 Link to this post

    If you call .kendoGrid(options) on an element that is not "on screen" (e.g. display: none) it does not render and function correctly.

    In particular the height, scrollbars and reorderable properties do not result in expected functionality.

    The following fiddle shows expected and  unexpected behaviors - via the use of a bootstrap tab control.

    Tab 1 - works as expected as this tab is visible on screen when the .kendoGrid(options) js call is made.

     Tab 2 and 3 - do not work as expected as they are not on-screen when the .kendoGrid(options) js call is made.

    1. You cannot re-order the columns via drag n drop.
    2. The scroll bars extend past the height set for the grid.
    (It's easier to see the the scroll bar rendering issues if you are not on a mac with on-demand scrollbars)

    http://jsfiddle.net/YNdAJ/3/

    The immediate work around is to call .kendoGrid(options) the first time each tab is displayed on screen however there is a significant delay while this processing occurs and I'd rather have all that happen at a different stage of the page load lifecycle.

    Is this a bug? If not, is there a better way to achieve what I'm looking for?
  2. Answer
    Robert
    Robert avatar
    38 posts
    Member since:
    Feb 2012

    Posted 23 Aug 2012 Link to this post

    I ran into this issue too, in the exact same situation (KendoUI + Bootstrap). I'll give you the solution Telerik came up with, but I'll guarantee you you're not going to be real thrilled about it. But i'm using it in production, and it works.

    The problem has to do with the order events take place, and how Kendo does the math to calculate the sizes for an area. In order for Bootstrap Tabs to work with Kendo, you have to initialize them with Javascript, and the container they are in (the div for the body area of the tab) has to be hidden by default.

    Given the following Bootstrap Tabs (I use the "pill" visual in this case):
    <ul class="nav nav-pills" id="financialSubNav">
        <li class="active"><a href="#rentroll">Rental Income</a></li>
        <li><a href="#otherincome">Other Scheduled Income</a></li>
        <li><a href="#operating">Operating Expenses</a></li>
    </ul>
    <div class="tab-content">
        <style scoped="scoped">
            .tab-content {
                display: inherit;
            }
        </style>
        <div class="tab-pane active" id="rentroll">
            <div id="rentRollGrid"></div>
        </div>
        <div class="tab-pane active" id="otherincome">
            <div id="otherIncomeGrid"></div>
        </div>
        <div class="tab-pane active" id="operating">
            <div id="operatingExpensesGrid"></div>
        </div>
    </div>

    Note the <style scoped="scoped"> tag inside the outer container for the tab bodies. This means that the style will only apply to the children. This one in particular overrides a Bootstrap style on divs that is the first part of the problem. Also note that every tab is set to active. This means their sizes will initially compute out in the DOM. We'll make it not suck in a moment.

    getKendoGrid = function(gridContainer, menuItem, autoBind, dataSource, columns, toolbar, dataBound, detailInit, height) {
        var grid = $(gridContainer).css("visibility", "hidden").kendoGrid({
            autoBind: autoBind,
            dataSource: dataSource,
            navigatable: true,
            editable: true,
            filterable: true,
            sortable: {
                mode: 'multiple'
            },
            pageable: {
                numeric: true,
                previousNext: false,
                refresh: true
            },
            scrollable: true,
            height: height == null ? 450 : height,
            toolbar: toolbar,
            columns: columns,
            dataBound: dataBound,
            detailInit: detailInit,
        }).css("visibility", "");
        if (menuItem != null) {
            $(menuItem).removeClass("active");
        }
        return grid;
    };

    And in my document.ready function, I call this:

    getKendoGrid("#rentRollGrid", null, false, rentalIncomeDataSource, rentalIncomeColumns, true,       kendoGridUpdateOnlyToolbar, financialsDataBound);
    getKendoGrid("#otherIncomeGrid", "#otherincome", false, otherIncomeDataSource, otherIncomeColumns, false, kendoGridToolbar, financialsDataBound);
    getKendoGrid("#operatingExpensesGrid", "#operating", false, operatingExpensesDataSource, operatingExpenseColumns, false, kendoGridToolbar, financialsDataBound);

    (omitted for brevity)

    $('#financialSubNav a').click(function(e) {
        e.preventDefault();
        $(this).tab('show');
    });

    The first parameter is the div that I'll be rendering the Grid in. If you go back to the getKendoGrid method, you'll see we take advantage of jQuery chaining to set the tab body's visibility to "hidden" (you can't use .hide() in this scenario, we need it to be calculated properly in the DOM, just not rendered). Then we do our Grid work, then the jQuery chaining comes back in, and we set the tab body's visibility to nothing, which clears the additional css as if it never existed.

    The 2nd parameter is the Bootstrap tab body that we are going to *clear* the active class from (that's why the first call passes a null parameter, because we want the first tab to stay active.)

    The other parameters let me compartmentalize my Grid components so they can be re-used on other pages, but that is another post for another time.

    The 2nd part (after the omitted section) bypasses the really awesome HTML5-ness of Bootstrap's automatic wireup, to manually configure the Bootstrap Tab UI. It is necessary because otherwise, Bootstrap configures everything before Kendo does it's thing, and we can't have that.

    I'm going to be covering this and other Kendo + Bootstrap issues in a series of blog posts, which I will link to in a few days once my site is live and the blog is up. At any rate, I hope this helps.

    Robert McLaws
    http://twitter.com/robertmclaws
  3. Kendo UI is VS 2017 Ready
  4. Ben
    Ben avatar
    2 posts
    Member since:
    Jul 2012

    Posted 23 Aug 2012 Link to this post

    Thanks for your reply.

    I ended up doing something similar. I added the "active" css class through js on each tab pane before initializing the grid and then removed the class straight after.

    I like how you  use the visibility:hidden css property to prevent any screen flicker. I'll add that to my approach.
     
    PS. You're right. I don't like the solution :)
  5. poet_byron
    poet_byron avatar
    21 posts
    Member since:
    Mar 2010

    Posted 05 Oct 2012 Link to this post

    I have found that if you call read after you make your containing element visible, that it will re-paint the grid properly.  This has not been tested in your scenario, but it has been tested with a modal window.  I.e:

            $("#dialogWindow").dialog('open');
            
            // Must call read again here because grid is not visible to begin with
            // and must be re-painted.
            $("#gridFull").data("kendoGrid").dataSource.read();


    Hope this helps.
Back to Top
Kendo UI is VS 2017 Ready