DataTables 1.10.12 - scrollX bug when grid is rendered inside a hidden div.

DataTables 1.10.12 - scrollX bug when grid is rendered inside a hidden div.

johnzabroskijohnzabroski Posts: 4Questions: 2Answers: 0

Hi,

This is not a question so much as a comment, that will hopefully help other developers who spent hours troubleshooting similar problems.

The scrollX functionality creates a bunch of separate divs, and for whatever reason he draw callback does not always correctly calculate the footer width. I believe this has something to do with the fact that the draw callback sets the width to 0px, and therefore causes the footer to not resize the same as the header because the footer doesn't have the sorting icon affordances. So, even though the footer cells have identical content to the header, they will always render with less width because they do not have the inserted sorting affordances.

The stupid workaround I have found that works is re-draw the table, then call sort twice. I have no idea why this works, but it does. If I had to guess, there is some peculiarity behind whether the table is "culled" by the graphics rendering engine. For example, if you have a tabbed UI and the grid is rendered on a hidden tab, then the calculations used by DataTables.Net will be off. This would explain why it gets assigned 0px - at the moment it is rendered, it has no layout.

Another solution would be to redraw the grid whenver the tab becomes visible.

Here is some TypeScript code which helps give people some clues:

        var $myTableId = $("#myTableId");
        var $dt = $myTableId.DataTable(<any>{
            "lengthMenu": [10, 20, 50, 100],
            "scrollX": true
        });

        $.ajax({
            url: route_url,
            method: "GET",
            dataType: "json"
        }).done(function (data: any) {
            data.forEach(function (val: any) {
                $dt.row.add([
                    val.id,
                    val.name,
                    val.a,
                    val.b,
                    val.c,
                    val.d,
                    val.e,
                    val.f,
                    val.g,
                    val.h,
                    val.i,
                    val.j,
                    val.k,
                    val.l,
                    val.m,
                    val.n,
                    val.o,
                    val.p,
                    val.q,
                    val.r,
                    val.s,
                    val.t,
                    val.u,
                    val.v,
                    val.w,
                    val.x,
                    val.y,
                    val.z,
                ]);
            }
            $dt.draw(true);
            $(".dataTables_scrollHead table.dataTable tr th:first-child", "#myTableId").click();
            $(".dataTables_scrollHead table.dataTable tr th:first-child", "#myTableId").click();
        }

HTML5 w/ Bootstrap4 alpha2:

<div class="table-responsive">
    <table id="myTableId" class="table table-striped table-bordered">
        <thead class="thead-inverse">
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>A is for Apple</th>
                <th>B is for Boy</th>
                <th>C is for Carrot</th>
                <th>D is for Doppelganger</th>
                <th>E is for Ebony</th>
                <th>F is for Faucet</th>
                <th>G is for Giraffe</th>
                <th>H is for Helium</th>
                <th>I is for Igloo</th>
                <th>J is for Joker</th>
                <th>K is for Key</th>
                <th>L is for Laughable</th>
                <th>M is for Money</th>
                <th>N is for Nancy</th>
                <th>O is for Oscar</th>
                <th>P is for Popular</th>
                <th>Q is for Query</th>
                <th>R is for Roger</th>
                <th>S is for Stanley</th>
                <th>T is for Titanium</th>
                <th>U is for Uranium</th>
                <th>W is for Watchmen</th>
                <th>X is for Xena Warrior Princess</th>
                <th>Y is for Yellow</th>
                <th>Z is for Zebra</th>
            </tr>
        </thead>
        <tfoot class="tfoot-inverse">
            <tr>
                <th>ID</th>
                <th>Name</th>
                <th>A is for Apple</th>
                <th>B is for Boy</th>
                <th>C is for Carrot</th>
                <th>D is for Doppelganger</th>
                <th>E is for Ebony</th>
                <th>F is for Faucet</th>
                <th>G is for Giraffe</th>
                <th>H is for Helium</th>
                <th>I is for Igloo</th>
                <th>J is for Joker</th>
                <th>K is for Key</th>
                <th>L is for Laughable</th>
                <th>M is for Money</th>
                <th>N is for Nancy</th>
                <th>O is for Oscar</th>
                <th>P is for Popular</th>
                <th>Q is for Query</th>
                <th>R is for Roger</th>
                <th>S is for Stanley</th>
                <th>T is for Titanium</th>
                <th>U is for Uranium</th>
                <th>W is for Watchmen</th>
                <th>X is for Xena Warrior Princess</th>
                <th>Y is for Yellow</th>
                <th>Z is for Zebra</th>
            </tr>
        </tfoot>
        <tbody>
        </tbody>
    </table>
</div>

CSS3:

table.dataTable,
table.dataTable th,
table.dataTable td,
.datatTables_scrollFootInner {
    -webkit-box-sizing: content-box;
    -moz-box-sizing: content-box;
    box-sizing: content-box;
}

See also, similar to the problems mentioned in this thread: https://datatables.net/forums/discussion/14342/column-header-not-aligned-with-column-data-with-horizontal-scrolling/p2

This question has an accepted answers - jump to answer

Answers

  • allanallan Posts: 61,879Questions: 1Answers: 10,138 Site admin
    Answer ✓

    Hi,

    If the DataTable is initialised in a hidden element, you must call columns.adjust() when it is made visible.

    The reason for that is that hidden elements have no height or width, so DataTables can't correctly align the columns while it is hidden.

    Allan

  • johnzabroskijohnzabroski Posts: 4Questions: 2Answers: 0

    Thanks, that seems much simpler and works just as well as my hack. I read the code and it has this comment:

     /**
     * Adjust the table column widths for new data. Note: you would probably want to
     * do a redraw after calling this function!
     *  @param {object} settings dataTables settings object
     *  @memberof DataTable#oApi
     */
    

    My question is: Why "probably"?

  • allanallan Posts: 61,879Questions: 1Answers: 10,138 Site admin

    Because you might want to do something else with the table before calling draw. For example you might want to filter the table.

    I think that comment is actually a little out of date now to be honest. It isn't really required to do a draw after columns.adjust() now. It used to be that it would help the alignment with a scrolling table, but that he handled automatically now, so I think that comment is a bit redundant these days.

    Allan

This discussion has been closed.