Sticky Table Header in ons-page



  • Hello,

    I try to make a Sticky-Table-Header in one of my ons-pages.
    For this I downloaded a little script which you can see below.
    The problem ist when I put my table in one of the <ons> tags the script stops working.
    I don’t know what I must change that the script recoginzes that i scrolled down/up.
    In the www i only find other script which work fine to… but only without Onsen.
    (I have marked the position where normally something changes)

    $(function(){
        $('table').each(function() {
            if($(this).find('thead').length > 0 && $(this).find('th').length > 0) {
                // Clone <thead>
                var $w     = $(window),
                    $t     = $(this),
                    $thead = $t.find('thead').clone(),
                    $col   = $t.find('thead, tbody').clone();
    
                // Add class, remove margins, reset width and wrap table
                $t
                .addClass('sticky-enabled')
                .css({
                    margin: 0,
                    width: '100%'
                }).wrap('<div class="sticky-wrap" />');
    
                if($t.hasClass('overflow-y')) $t.removeClass('overflow-y').parent().addClass('overflow-y');
    
                // Create new sticky table head (basic)
                $t.after('<table class="sticky-thead" />');
    
                // If <tbody> contains <th>, then we create sticky column and intersect (advanced)
                if($t.find('tbody th').length > 0) {
                    $t.after('<table class="sticky-col" /><table class="sticky-intersect" />');
                }
    
                // Create shorthand for things
                var $stickyHead  = $(this).siblings('.sticky-thead'),
                    $stickyCol   = $(this).siblings('.sticky-col'),
                    $stickyInsct = $(this).siblings('.sticky-intersect'),
                    $stickyWrap  = $(this).parent('.sticky-wrap');
    
                $stickyHead.append($thead);
    
                $stickyCol
                .append($col)
                    .find('thead th:gt(0)').remove()
                    .end()
                    .find('tbody td').remove();
    
                $stickyInsct.html('<thead><tr><th>'+$t.find('thead th:first-child').html()+'</th></tr></thead>');
    
                // Set widths
                var setWidths = function () {
                        $t
                        .find('thead th').each(function (i) {
                            $stickyHead.find('th').eq(i).width($(this).width());
                        })
                        .end()
                        .find('tr').each(function (i) {
                            $stickyCol.find('tr').eq(i).height($(this).height());
                        });
    
                        // Set width of sticky table head
                        $stickyHead.width($t.width());
    
                        // Set width of sticky table col
                        $stickyCol.find('th').add($stickyInsct.find('th')).width($t.find('thead th').width())
                    },
    
                    repositionStickyHead = function () {
                        // Return value of calculated allowance
                        var allowance = calcAllowance();
                                            
                    
                        // Check if wrapper parent is overflowing along the y-axis
    //
    // Here it normally does something when it is used without Onsen
    //
                        if($t.height() > $stickyWrap.height()) {
                            // If it is overflowing (advanced layout)
                            // Position sticky header based on wrapper scrollTop()
                            if($stickyWrap.scrollTop() > 0) {
                                // When top of wrapping parent is out of view
                                $stickyHead.add($stickyInsct).css({
                                    opacity: 1,
                                    top: $stickyWrap.scrollTop()
                                });
                            } else {
                                // When top of wrapping parent is in view
                                $stickyHead.add($stickyInsct).css({
                                    opacity: 0,
                                    top: 0
                                });
                            }
                        } else {
                            // If it is not overflowing (basic layout)
                            // Position sticky header based on viewport scrollTop
                            if($w.scrollTop() > $t.offset().top && $w.scrollTop() < $t.offset().top + $t.outerHeight() - allowance) {
                                // When top of viewport is in the table itself
                                $stickyHead.add($stickyInsct).css({
                                    opacity: 1,
                                    top: $w.scrollTop() - $t.offset().top
                                });
                            } else {
                                // When top of viewport is above or below table
                                $stickyHead.add($stickyInsct).css({
                                    opacity: 0,
                                    top: 0
                                });
                            }
                        }
                    },
                    repositionStickyCol = function () {
                        if($stickyWrap.scrollLeft() > 0) {
                            // When left of wrapping parent is out of view
                            $stickyCol.add($stickyInsct).css({
                                opacity: 1,
                                left: $stickyWrap.scrollLeft()
                            });
                        } else {
                            // When left of wrapping parent is in view
                            $stickyCol
                            .css({ opacity: 0 })
                            .add($stickyInsct).css({ left: 0 });
                        }
                    },
                    calcAllowance = function () {
                        var a = 0;
                        // Calculate allowance
                        $t.find('tbody tr:lt(3)').each(function () {
                            a += $(this).height();
                        });
                        
                        // Set fail safe limit (last three row might be too tall)
                        // Set arbitrary limit at 0.25 of viewport height, or you can use an arbitrary pixel value
                        if(a > $w.height()*0.25) {
                            a = $w.height()*0.25;
                        }
                        
                        // Add the height of sticky header
                        a += $stickyHead.height();
                        return a;
                    };
    
                setWidths();
    
                $t.parent('.sticky-wrap').scroll($.throttle(250, function() {
                    repositionStickyHead();
                    repositionStickyCol();
                }));
    
                $w
                .load(setWidths)
                .resize($.debounce(250, function () {
                    setWidths();
                    repositionStickyHead();
                    repositionStickyCol();
                }))
                .scroll($.throttle(250, repositionStickyHead));
            }
        });
    });
    


  • @Martin Can you post your html code as well? Basically, you should just have a table in an <ons-page> and you should be good to go.



  • Hello, until monday i have no access to the code but it is a normal table in an <ons-page> tag.
    I solved it by placing my table outside of all the onsen tags. It worked but is not the best solution.

    <ons-page>
    <tabel>
          <thead>
               <tr>
                    <td>
                           Head
                    </td>
                     <td>
                          Columns
                    </td>
                </tr>
           </thead>
            <tbody>
                <tr>
                   <td>
                          Body
                   </td>
                  </tr>
                </tbody>
    </table> 
    </ons-page>


  • @Martin I haven’t used the plugin, but with the table code you just posted it is malformed. You need an additional td cell in the body or a colspan=2. I doubt that had an issue, but it could. Also, do you have just one table or multiples? I ask because the first thing that comes to mind with the jquery, is it may not be seeing the table. So to resolve that, you could give the table an ID and reference that instead of the tag.



  • @munsterlander I have a lot of td in the body. I create the table dynamic so there are at least 365. And the idea that jquery mayber doesn’t find my table can’t be. The reson why it can’t be is that wihout the ons-page it works. 100% same table. I will test it in the upcoming days.Pperhaps I’m completly wrong but i don’t think so.


Log in to reply