I have a dashboard with some widgets grouped into tabs that the user can click through. The widgets have a default start height, and when the content (charts, graphs, tables etc.) they contain renders their heights get updated.
I currently update the heights of the widgets in only the active tab on page load and then when the user clicks a different tab update those widgets.
I'm having to use a setTimeout
to make sure the active tab is visible before updating the heights, which means the widgets slide down momentarily after a click rather than appearing at their optimum height immediately.
display:none
?I tried using :visible
and :hidden
selectors but it didn't work.
setTimeout
since I'm only guessing that 200ms will be enough of a delay.Example below, plus Codepen.
$(document).foundation();
$(function () {
var options = {
cellHeight: 40,
verticalMargin: 28,
animate: true,
};
widgetsInit = function(options) {
var targetPanel = '.tabs-panel.is-active';
setTimeout(function(){
$(targetPanel + ' .grid-stack').gridstack(options);
$(targetPanel + ' .grid-stack .grid-stack-item').each(function(i){
$(targetPanel + ' .grid-stack').data('gridstack').resize(
$(targetPanel + ' .grid-stack .grid-stack-item')[i],
$($(targetPanel + ' .grid-stack .grid-stack-item')[i]).attr('data-gs-width'),
Math.ceil(($(targetPanel + ' .grid-stack .grid-stack-item .grid-stack-item-content')[i].scrollHeight + $(targetPanel + ' .grid-stack').data('gridstack').opts.verticalMargin) / ($(targetPanel + ' .grid-stack').data('gridstack').cellHeight() + $(targetPanel + ' .grid-stack').data('gridstack').opts.verticalMargin))
);
});
}, 200);
}
widgetsInit(options);
$('.tabs-title').on('click', function(e) {
widgetsInit(options);
})
});
.grid-stack > .grid-stack-item > .grid-stack-item-content {
background-color: #fff;
cursor: move;
border: 1px solid #e3e3e3;
border-radius: 4px;
padding: 1rem;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.4.0/gridstack.min.css" rel="stylesheet"/>
<link href="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.4.3/css/foundation.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.4.0/gridstack.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.4.0/gridstack.jQueryUI.min.js'></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/foundation/6.4.3/js/foundation.min.js"></script>
<!-- Tabs start -->
<ul class="tabs dashboard-tabs" data-tabs id="example-tabs" data-deep-link="true" data-update-history="true" data-match-height="false">
<li class="tabs-title is-active"><a href="#panel1" aria-selected="true">Panel 1</a></li>
<li class="tabs-title"><a href="#panel2">Panel 2</a></li>
</ul>
<!-- Tabs end -->
<!-- Panels start -->
<div class="tabs-content unstyled" data-tabs-content="example-tabs">
<!-- Panel 1 start -->
<div class="tabs-panel is-active" id="panel1">
<div class="grid-stack">
<div class="grid-stack-item" data-custom-id="0" data-gs-x="0" data-gs-y="0" data-gs-width="4">
<div class="grid-stack-item-content">
#0<br>
<iframe width="560" height="315" src="https://www.youtube.com/embed/VUuBJ0ietME" frameborder="0"></iframe>
</div>
</div>
<div class="grid-stack-item" data-custom-id="1" data-gs-x="4" data-gs-y="0" data-gs-width="4">
<div class="grid-stack-item-content">
#1
</div>
</div>
<div class="grid-stack-item" data-custom-id="2" data-gs-x="8" data-gs-y="0" data-gs-width="4">
<div class="grid-stack-item-content">#2</div>
</div>
<div class="grid-stack-item" data-custom-id="3" data-gs-x="0" data-gs-y="1" data-gs-width="8">
<div class="grid-stack-item-content">#3</div>
</div>
</div>
</div>
<!-- Panel 1 end -->
<!-- Panel 2 start -->
<div class="tabs-panel" id="panel2">
<div class="grid-stack">
<div class="grid-stack-item" data-custom-id="4" data-gs-x="0" data-gs-y="0" data-gs-width="6">
<div class="grid-stack-item-content">
#4<br>
<iframe width="560" height="315" src="https://www.youtube.com/embed/a4fv-BtzNmY" frameborder="0"></iframe>
</div>
</div>
<div class="grid-stack-item" data-custom-id="5" data-gs-x="6" data-gs-y="0" data-gs-width="6">
<div class="grid-stack-item-content">#5</div>
</div>
</div>
</div>
<!-- Panel 2 end -->
</div>
<!-- Panels end -->
There are a few things at play here. I've created a fork on how I would handle it. https://codepen.io/matthewblewitt/pen/KeybxG
I've triggered the gridstack plugin with the foundation tabs API rather than a click event so you can remove the setTimeout.
$(document).on('change.zf.tabs', function(e) {
widgetsInit(options);
});
The foundation tabs hide inactive tabs with display: none
and the gridstack plugin doesn't seem to play nice with that property. So I've changed the CSS to hide inactive tabs off screen instead and fade them with CSS opacity and disabled gridstack's animations.
.tabs-panel {
position: absolute;
overflow: hidden;
height: 1px;
width: 1px;
opacity: 0;
transition: 0.75s opacity ease;
display: block;
}
.tabs-panel.is-active {
position: static;
overflow: visible;
width: auto;
height: auto;
opacity: 1;
}
Hope this helps.