Closed ashokprajapati closed 1 year ago
The same issue here, HELP NEEDED! Set the height of each grid based on their inner contents!
have been pulling my hair for the last 2 days, any reply would be highly appreciated!
I believe that what you're asking about can be done with CSS and DOM manipulation. If either of you could provide a jsFiddle, I'd be happy to help achieve the desired outcome.
Hi Radiolips
here have more info i have drag and drop element, every drag have his one html contain inside
please see this url http://webiberis.com/project/gridstack/demo/
there have 2 div (drag me element ) in this div have image, when i will drag and drop in gridstak element then it's show image inside gridstack container, but in gridstack container have scroll bar and have fixed height
there i need full height same as image height without scrolling.
and there i want height as per image height without spacing and scroll bar
Hi & thanks for your reply @Radiolips, @ashokprajapati has already provided an example, but here is a jsfiddle example for you: https://jsfiddle.net/web2fix/3psxL32L/
Please note the section called MIDDLE and sidebars which have scrollbars, I would like to have the scrollbar removed and update the height of each container (or grid) as much as their inner contents go!
That would be really nice if I could have that on initialization. I have taken a look at the source and I saw that there is an "auto" option for cellHeight so it would be nice to be able to pass a variable like "dynamic" which could read the $(content's).scrollHeight for each grid and set it as cellHeight for that (each) grid.
isAutoCellHeight = this.opts.cellHeight === 'auto'; isDynamicCellHeight = this.opts.cellHeight === 'dynamic'; if (isAutoCellHeight) { self.cellHeight(self.cellWidth(), true); } else if (isDynamicCellHeight) { // then get the height of each inner container and calculate it as a grid height or in this case cellHeight } else { this.cellHeight(this.opts.cellHeight, true); } ;
I tried to fix this issue temporarily but something is not right with the cellHeight I set the cellHeight to be 1 pixell then calculated the inner height and passed to the divs as data-gs-height="calculated inner height"
then this happened: the columns are now extremely long! even some of them do not have any contents. some columns are supposed to have just 100px height but they are going insanely longer than 100px extremely in need of your help @radiolips! example after the dirty fix which brings up the cellHeight bug: jsfiddle
Help still needed! I am still pulling my hair! has been a week. Let me know if this can not be done with grid stack. Just saying that "It can be done with CSS and DOM manipulation" will not solve our issue!
i also want answer for this question.
I believe this is one of the most important features that should be included! I have the same issue working around is not as easy as @radiolips says! I have been working around for days and no results! css manipulation does not work and javascript height recalculation after initialization also slows down the loading time! The only one way to fix this is on initialization through the plugin itself. if you think otherwise then prove it @radiolips!
Is there a solution to this yet? @radiolips @webdesignmzm
Also looking for a solution to this, any updates?
I am looking for solution as well.
Apologies for the delay.
Firstly, @webdesignmzm and @somchaisomsi, I'd like to point out that this library, and the support everyone receives, is entirely free of charge. Please be more considerate to the contributors who are spending their own time to provide a better dashboard experience for all users.
I am closing this ticket. Before closing it, I will say (note that I am now now, nor have I anywhere on this ticket, said the word "easy") that this can be done using Javascript and CSS. This Stack Overflow article (http://stackoverflow.com/questions/2522579/how-do-i-get-the-real-height-of-a-overflow-hidden-or-overflow-scroll-div) explains how to grab the height of a div with a scrollbar. If you put this code into a setTimeout
or if you run it onchange
from gridstack, you'll have widgets that have height that auto-update based on content. Width may be adjusted the same way. I have built this code based on @ashokprajapati 's link.
$('.grid-stack').data('gridstack').resize(
$('.grid-stack-item')[5],
$($('.grid-stack-item')[5]).attr('data-gs-width'),
Math.ceil(($('.grid-stack-item-content')[5].scrollHeight + $('.grid-stack').data('gridstack').opts.verticalMargin) / ($('.grid-stack').data('gridstack').cellHeight() + $('.grid-stack').data('gridstack').opts.verticalMargin))
);
This code simply calls resize
on a widget, doesn't change its width, and updates its height to be the correct math to determine height (this assumes verticalMargin
is in pixels).
FYI for people coming in later, I've found that it works a little better if you use round instead of ceil.
var grid = $('.grid-stack').data('gridstack');
var gsi = $(elemId).parents(".grid-stack-item");
var newHeight = Math.round((gsi[0].scrollHeight + grid.opts.verticalMargin) / (grid.cellHeight() + grid.opts.verticalMargin));
grid.resize(gsi,$(gsi).attr('data-gs-width'),newHeight);
@SimonOrdo Could you explain why using Math.round
would be better? If the content is even one pixel over x
height, height should be set to x+1
- thus, Math.ceil
is the recommended option.
@SimonOrdo Hi Thanks, would you please care to update the following example from @somchaisomsi with your code? I can't get it to work! NEW LINK: https://jsfiddle.net/W2F/4yqjux2c/
Would you please send us the updated js fiddle link?
@SimonOrdo @radiolips at first I thought Math.round indeed works better. With Math.ceil the item always becomes a bit larger than expected when doing a manual resize. At first I couldn't find any situation where the item is not large enough when using round. However, after some more testing I ran into some issues when using round instead of ceil where the height wouldn't be large enough, thus resulting in a vertical scrollbar, which I would like to prevent. Using ceil fixes this problem, but causes some other issues:
overflow-y: hidden
on the grid-stack-item-content.Any help with the other problems would be greatly appreciated!
I am trying to check that gridstack panel takes height based on its inner container height. I was using the code of responsive.html file which I downloaded from gridstack. I just put some new line in the div to see if it is expanding or not. My changed code is:
<div class="content-wrapper">
<div class="grid-stack">
</div>
</div>
<script type="text/javascript" src="../asset/chroma.js-master/chroma.js"></script>
<script type="text/javascript">
$(function () {
// thanks to http://stackoverflow.com/a/22885503
var waitForFinalEvent=function(){var b={};return function(c,d,a){a||(a="I am a banana!");b[a]&&clearTimeout(b[a]);b[a]=setTimeout(c,d)}}();
var fullDateString = new Date();
function isBreakpoint(alias) {
return $('.device-' + alias).is(':visible');
}
var options = {
float: false
};
$('.grid-stack').gridstack(options);
function resizeGrid() {
var grid = $('.grid-stack').data('gridstack');
if (isBreakpoint('xs')) {
$('#grid-size').text('One column mode');
} else if (isBreakpoint('sm')) {
grid.setGridWidth(3);
$('#grid-size').text(3);
} else if (isBreakpoint('md')) {
grid.setGridWidth(6);
$('#grid-size').text(6);
} else if (isBreakpoint('lg')) {
grid.setGridWidth(12);
$('#grid-size').text(12);
}
};
$(window).resize(function () {
waitForFinalEvent(function() {
resizeGrid();
}, 300, fullDateString.getTime());
});
new function () {
this.serializedData = [
{x: 0, y: 0, width: 4, height: 4},
{x: 4, y: 0, width: 4, height: 4},
{x: 8, y: 0, width: 4, height: 4},
{x: 0, y: 4, width: 6, height: 4},
{x: 6, y: 4, width: 6, height: 4}
];
this.grid = $('.grid-stack').data('gridstack');
this.loadGrid = function () {
this.grid.removeAll();
var items = GridStackUI.Utils.sort(this.serializedData);
_.each(items, function (node, i) {
this.grid.addWidget($(layout("pie", node.id)),
node.x, node.y, node.width, node.height);
}, this);
return false;
}.bind(this);
this.loadGrid();
resizeGrid();
};
});
</script>
But the div is not at all expanding. I did not understand how I will use the solution provided by @radiolips . Where shall I change the code.
The following is an alternate solution to dynamically size a grid cell based on its content using the grid's update
function. Here widgetInstance
is a reference to the widget object and grid
is the grid object:
let contentElement = widgetInstance.el.querySelector(".grid-stack-item-content").children[0].children[0]; let contentHeight = Math.ceil((contentElement .parentElement.clientHeight * 1.05) / grid.opts.cellHeight); // Get height in rows. Multiply by 1.05 for some buffer contentElement.parentElement.parentElement.style.overflow = "hidden"; // Hide scrollbars if desired grid.update(widgetInstance.el, {h: contentHeight});
I think it's time to re-open this and do it the right way if someone is willing to donate or contribute a review. some sort of contentHeight option on the grid/gridItems....
@jasondalycan Math.ceil()
ought to be enough without 5% fuge (whcih can be a lot), but you are missing is taking the padding off (default is 10px on each side) before finding a fit.
Also your element is specific to your use case of course. widgetInstance.el.querySelector(".grid-stack-item-content") should be enought if you don't overflow:hidden.
but you are right my new update()
method will do once you find that row number, until somethng resizes and you get notified (that the tricky part and when the DOM has the wanted size loaded)
Not sure if this is helpful, but figured I'd share. Forgot about this issue years ago and saw the email about reopening. Been using the following code for years and works well for my use-case.
In retrospect while typing this up, I'd probably put this in the "conceptual" category of things.. @jasondalycan has a cleaner solution, that is.
And in that the only mathematical value added here is the usage of scrollheight
, and maybe factoring hard horizontal padding (which stretches the item contents vertically the smaller it gets, like a margin).
Fundamentally it's just a window resize event adjustment, and it's not perfect. I think the "threshold" part is wonky and needs improved. Majority of the time, it gets it right though without overflow.
jQuery.fn.getElementAspects = function () {
return {
border: [
$(this).outerWidth() - $(this).innerWidth(),
$(this).outerHeight() - $(this).innerHeight()
],
padding: [
$(this).innerWidth() - $(this).width(),
$(this).innerHeight() - $(this).height()
],
margin: [
$(this).outerWidth(true) - $(this).outerWidth(),
$(this).outerHeight(true) - $(this).outerHeight()
]
};
};
(function ($, sr) {
// debouncing function from John Hann
// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
var debounce = function (func, threshold, execAsap) {
var timeout;
return function debounced() {
var obj = this, args = arguments;
function delayed() {
if (!execAsap)
func.apply(obj, args);
timeout = null;
};
if (timeout)
clearTimeout(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = setTimeout(delayed, threshold || 100);
};
}
// smartresize
jQuery.fn[sr] = function (fn) { return fn ? this.bind('resize orientationchange', debounce(fn)) : this.trigger(sr); };
})(jQuery, 'smartresize');
$(document).ready(function() {
var options = {
cellHeight: 'auto', // unsure if necessary or even impactful. but this is how i have it.
};
var grid = GridStack.init(options, $('#my-grid') );;
// initial refresh. Depending on your load style, you may want to drop this into a setTimeout.
handleGridResize(grid);
// and when window resizes:
$(window).smartresize(function () {
handleGridResize(grid);
});
});
// resize the grid based on inner contents. Should be called when content changes, or when page loads or resizes.
function handleGridResize(grid) {
var targets = $('.grid-stack-item:not(.grid-stack-placeholder)');
if (targets.length < 1) return;
var CELL_HEIGHT = grid.cellHeight();
targets.each(function () {
var the_content = $(this).find('.grid-stack-item-content .gsi-content');
var el = (the_content[0]);
var el_height = el.scrollHeight;
var diff = el_height % CELL_HEIGHT; // remainder between real height and the gridstack fed calculated height. ("how far off are we from reality")
// keep in mind that these are GRID size values, not pixel. 1,2,4,6,8,10,12.
var height = Math.floor(el_height / CELL_HEIGHT); // difference between actual REAL height & gridstack's
var width = $(this).attr('data-gs-width'); // user preference, direct feed. Default value passed to the resize func below.
var threshold = the_content.parent().getElementAspects().padding[0];
// when the difference between actual content height differs from the decided-height by gridstack.. (ie. overflow detected)
// and that difference is greater than the horizontal padding on both sides(2x) + some buffer tolerance (thus 3x) (to increase likelihood of occurrence)..
// we should then set the height to the next-highest grid size
if (diff>0 && diff!=el_height && diff > threshold/3) {
height = Math.ceil( el_height / CELL_HEIGHT );
}
grid.resize(
$(this)[0],
width,
height
);
});
}
this is very application specific as how tall a widget needs to be is highly depends on your specific content layout/DOM heirarchy. Here is code I just added in my Angular app for reference if it helps someone (comment to map to GS classes). I call this whenever content changes, or grid resizes.
I don't think I can move this into the generic lib I'm afraid, as it assumes content takes available space, while first and only child is sized for content and would clip in my case.
/** Call to make the gridItem match the content height of the finished loaded widget */
public resizeToContent() {
const el = this.el; // .grid-stack-item
if (!el) return;
let height = el.getBoundingClientRect().height;
const card = el.querySelector('.card-block'); // .grid-stack-item-content that fills remaining space between header+footer
if (!card) return;
const cardH = card.getBoundingClientRect().height;
const contentH = (card.firstChild as Element)?.getBoundingClientRect().height || cardH; // actual widget inside that may clip out or have extra space
height += contentH - cardH;
const grid = this.grid.grid; // GridStack
const cell = grid?.getCellHeight();
if (!cell) return;
let h = Math.ceil(height / cell);
const opt = this.options; // GridStackWidget
if (opt.maxH && h > opt.maxH) h = opt.maxH;
if (h !== opt.h) grid.update(el, {h});
}
Note: this bypass the needs to know the padding/margin as it just figure out how big it is vs how much bigger to fit the content unclipped and size the outside accordingly.
fixed in the next release v9! even though items have height=1 to start with they are sized to content and reflow as needed...
long overdue feature - don't forget to donate to help support this lib!
https://github.com/gridstack/gridstack.js/assets/3496166/1e17d175-12d1-4ca9-af12-d70d957f90de
@adumesny is this feature already available to use in production? i just updated to 8.4.0 right now but still cant see the fitToContent
option
as I mentioned it will be in v9 - still need to consume it in my app and test it some more...
works for nested grid too!
https://github.com/gridstack/gridstack.js/assets/3496166/c9403321-f620-4478-8fac-b80945fbdaea
I want height as per inner container, i do not want any scroll bar and i want to put image inside grid-stack-item-content and i want grid-stack-item height same as image Height,
i have tried but i do not get result, can please let me know it;s possible