I'm writing an application where the resulting dgrid may have a different number of columns/column-widths depending on the input. Note the following two screenshots. The first one only has a few select fields, and the cells/data render nicely horizontally. the second query has many select fields, and as you can see renders undesirably as it attempts to fit all the cells into one screen cluttering the data. Note the dgrid is also sitting within a dijit BorderContainer.
Screenshot 1 (Small SELECT fieldset, renders ok)
Screenshot 2 (Large SELECT fieldset, renders undesirably
There will be a number of issues to contend with here, but I guess my main question is:
is there a css rule (or any other way - a dgrid function/event?) I can use to specify for the cells to expand to use the full width of the data within it without cutting it off (ie no overflow)? This would then need the grid to be displayed with a horizontal scrollbar. So I'd like the data to drive the width of the grid, rather than setting the width. I tried .dgrid-cell { white-space:nowrap; } but this seemed to be ignored. It almost seems like a span needs to be added inside of the cell, which would have the above css rule?
Secondarily - the next issue will be determining in which cases I should apply the above rule, vs the cases where the data DOES fit in the screen. In those situations it may be best to just let the table use the 100% width as per the first screenshot. any input on this one?
Thanks
Here I the way I set a grid cell width based on data. This is for a datagrid obj but you probably need to make a few adjustments for dgrid obj.
There are a few steps:
1) Create a <div> tag in your html call test
<div id="test"></div>
2) Loop through the data for each column in the grid and capture the largest width of the data for that column using javascript like:
var fnt_sz = '9pt';
var tst_item = window.document.getElementById("test");
tst_item.style.fontSize = fnt_sz;
var widthPX = 45; //default px width
for (var i = 0; i < columns.length; i++) {
tst_item.innerHTML = columns[i]; //columns array represents data that will display for the column
widthPX = (tst_item.clientWidth + 1); //Give width in PX of the data pad it a bit as needed
}
Important items here include setting the appropriate font-size (fnt_sz), looping though all the column data to find the largest width in PX for the column. Use the largest widthPX for the column to set the column width in your layout object for the datagrid.
3) When creating the layout JSON data for your datagrid, set the width for each column (Max data widthPX for the column). Something like:
var build_layout = " var layout = [[{'name': 'ID', 'field': 'id', 'width': '17px'},";
for (var i = 0; i < cols.length; i++) {
build_layout += "\n{'name': '" + cols[i] + "', 'field': 'col" + (i+1) + "', 'width': '" + widths[i] + "px'},";
}
build_layout += "]];";
eval(build_layout);
/*create a new grid*/
var grid = new DataGrid({
id: 'grid',
store: store,
structure: layout, //Use layout JSON data which has width: xxpx; set for each column
rowSelector: '20px',
style: 'font-size:9pt',
rowsPerPage: 1000,
columnReordering: true,
autoWidth: true,
autoHeight: autoH});
When the grid displays, it should look good in any browser and all data should be visible because the column width PX value is greater than the largest data item for that column.. Should be easy enough to add a max px value for each column so things don't get out of hand with the width.
This is a bit of a pain in the $ss and should be a property of the dojo datagrid object but......
Here is what I end up with going through these steps:
Related
I would like to set a fixed width on the first column for lightning:datatable
I have already tried adding a initialWidth property to a column but it did not work. Adding .THIS tr :first-child {width: 800px !important;} in CSS file did set custom witdh on the column but it gets overlapped by the next column. My idea is that the style gets overridden by salesforce in the rendering phase. Therefore I tried to set it in the Renderer.js in afterRender function but I can't get it to work. Here is the code I wrote so far
afterRender: function (component, helper) {
this.superAfterRender();
var table = document.getElementById('subscriptionsTable');
var rows = table.getElementsByTagName('tr');
for (var i=0; i<rows.length; i++) {
rows[i].firstChild.style.width = '810px !important';
}
If you have any other ideas on how to achieve a custom column width please let me know. Thanks
The scrollX option in Datatables allows the user to scroll the grid horizontally - however, in my table, I am needing to keep the first two columns in place, but allow the next x columns scroll horizontally. I'm not seeing any good examples of how to do this.
Example:
https://datatables.net/examples/basic_init/scroll_x.html
You could achieve this by changing the relative position of each cell based on the scrollLeft value.
$('.dataTables_scrollBody').scroll(function (){
var cols = 2 // how many columns should be fixed
var container = $(this)
var offset = container.scrollLeft()
container.add(container.prev()).find('tr').each(function (index,row){ // .add(container.prev()) to include the header
$(row).find('td, th').each(function (index,cell){
if(index>=cols) return
$(cell).css({position:'relative',left:offset+'px'})
})
})
})
Okay now.. I really didn't know how to give this one a title. Here is my problem. I am trying to make a page where the body has a class defining the width of another div a.k.a baser.
I have a jQuery script that detects the width of the window and gives body a class hereafter. for example when the width of the window is about 900px - body will be given a class .col_6.
Each card is 150px in width, but when they have the additional class large they will be 300px in width. The problem now is that depending on the order of the cards in HTML, there will be some empty spaces if a card.large should be placed in a space only 150px wide. Then the card will automatically jump to next row and leave an open space of 150px in the previous row.
What I would like to know is - what can I add to my script to perhaps selecting a 150px wide card placed later in the order and move it in the empty spot or filling out the empty spot with a javascript made div ( for other purposes )..
I hope you are able to figure out my problem by reading this.. I have made a jsfiddle that shows my code and the problem. You can try resizing the window when reading the fiddle. It will show you how an empty space will be seen sometimes.
http://jsfiddle.net/EK8q2/4/
here is my javascript/jQuery if it can help you any way..
$(document).ready(function() {
winResize(window.innerWidth);
});
$(window).resize(function() {
winResize(window.innerWidth);
// Room for more functions
});
function winResize(w) {
resizeBaser(w);
// Room for more functions
}
function resizeBaser(w) {
var index = Math.min(10, Math.floor(w / 150));
if (index > 0) {
$('body').alterClass('col_*', 'col_' + index);
}
}
The algorithm as I see it is this:
Attach to load/scroll/resize events:
$(window).on('load scroll resize', function () {
});
There, group the $('.card') elements into an array of rows.
Something like:
var rowsObj = {}, rows = [];
$('.card').each(function(){
var el = $(this),
pos = el.position(),
currentRow = rowsObj[pos.top] || (rowsObj[pos.top] = []);
currentRow.push(el);
});
$.each(rowsObj, function(k, v) {
if (/^\d+(\.\d+)?$/.test(k)) {
rows.push(v);
}
});
// rows now contains array of arrays of $-ed elements
3. Then I'd enumerate the rows from end to start and tried to id all orphan cards (condition: single most narrow card) - having these, I'd search from top to bottom and tried to locate the possible new row (i.e. the last element of that potential row) and orphan.insertAfter(thatElement). Upon insertion, I'd exclude both rows (one containing the orphan, the other - incomplete row) from the array. Do until no pairs (orphan-incomplete) can be formed.
4.Then I'd think on how to extend this logic to widths larger than single card.
Please don't consider my question as a duplicate. I just din't succeed trying Display divs with different sizes with CSS
As suggested in the above post i used Masonry. But failed to get it worked. I am using codeigniter.
Here are the css i am using
#container {
width:90%;
margin:3% 0px 0px 10%;
}
.item {
margin:10px 10px 10px 10px;
float:left;
width:240px;
border:5px solid #f0f0f0;
background-color:#d2dbde;
border-radius:5px;
}
Javascript and js files
<!-- include js files -->
<script type="text/javascript" src="http://www.myappdemo.com/KarmakExpo/js/jquery.min.js"></script>
<script type="text/javascript" src="http://www.myappdemo.com/KarmakExpo/js/jquery.masonry.min.js"></script>
<script type="text/javascript">
$(function() {
$('#container').masonry({
// options
itemSelector : '.item'
});
});
</script>
content
<div id="container">
<div class="item">
<div id="usericon" style="width:240px;height:30px;">
<!-- content -->
</div>
<div id="name">
<!-- content -->
</div>
<div>
<a href="<?php echo $link; ?>">
<img src="<?php echo $picture = ($picture == null) ? '' : $picture; ?>" width="240px" height="auto">
</a>
</div>
I am displaying images,name,date etc in div section
Dynamic divs put in their place
JsFiddle - Demo (number of columns depends on width of document window).
Since it appears you have divs of regular widths, you might try something like this:
Note: Since first answering with this simple demo script, I have substantially altered the linked jsFiddle demo. It now barely resembles this code, but the basics are pretty much the same.
CSS kinda like this
div.column {
display:inline-block; /* "Columns" should be only as wide as their setting, */
vertical-align:top; /* should sit next to each other horizontally, */
width:240px; /* and be vertically aligned. */
height:auto;
margin:10px 0px 10px 10px;
}
div.column div.row {
width:240px; /* All "row" divs are of the same width, */
height:auto; /* but of varying heights */
margin:0px 0px 10px 0px;
padding:0px;
background-color:#00f0f0;
}
JavaScript kinda like this
(function () {
var tdw = 240 + 0 + 10; // Div width + margin-left + margin-right
window.addEventListener("load", function () {
var ww = window.innerWidth, // how much width to play with?
cn = Math.floor(ww / tdw), // how many columns will fit?
cdl = [], // memory
lc = 0, // alternation
c = 0, // iteration
ncd; // element object
while (c++ < cn) {
ncd = document.createElement("div"); // create columns
ncd.setAttribute("class", "column"); // set their class
document.body.appendChild(ncd); // add to page
cdl.push(ncd); // remember them
}
c = 0;
while (c++ < 100) { // this for demo // loop until there're no more
ncd = document.createElement("div"); // create your divs
// this could be where you add your div content
ncd.setAttribute("class", "row"); // set their class
lc = lc < cdl.length ? lc : 0; // alternate column as parent
cdl[lc++].appendChild(ncd); // add the div to the column
ncd.style.height = (200 * Math.random()) + "px"; // this for demo
// or you could add the content via innerHTML
}
}, false);
}());
This answer was put together whilst assuming a lot. With more detail in the question, I could have provided a more complete answer.
Since being asked to explain...
As I understand the question, it is to find a way to take dynamic information (extracted from where is irrelevant), and fill divs with it. Each of those divs is to be set on the page (presumably within a "feed" container or similar) in columns. Since the width of these (lets call them "infodivs") infodivs is of a set width, we can create columns of fixed widths to contain them. Now the divs are free to be whatever height they need to be (according to the info they contain), and will simply stack up on top of each other, within their parent div.column.
On page load we measure the available width (in a live version accounting for offsets etc), and calculate how many columns will fit horizontally, then create those columns. To save reading and re-reading the DOM, we can store the columns to an array for easy look-up later.
After creating the columns, we are free to add the dynamically created infodivs to the columns, cycling through the column look-up array, utilizing each progressive column (left to right across the screen) for each new infodiv. Once we get to the last column, we set the look-up counter back to zero, and continue loading infodivs.
The method results in each column being filled with an approximately equal number of info divs (dependant on maths). There is however no check of the height of each infodiv, so any column could end up with much longer content than the others. A way around this would be to measure the height of each column as each new infodiv is created, then add that infodiv to the column which is shortest. This would result in columns remaining more closely equal in height.
Note: The demonstration jsFiddle connected to this answer now contains a rudimentary function to dynamically measure the column heights as infodivs are being created. In order to get an accurate reading of the column height(s), each image has a temporary onload listener attached which triggers the creation of the next infodiv. The listener is removed as soon as it's done it's job to free up resources. This method slows overall page loading, but not enough to be impractical. Depending on real circumstances, faster less accurate loading might be more desirable. In that case, discard the image's onload listeners and create infodivs on demand regardless of the state of those previously created.
Further to dynamic measurement: The loading of large amounts of data and/or images (especially images) could be improved by the addition of an onscroll listener triggering a function to load new data (infodivs in this case) only when the visitor is scrolling toward the end of what they already see. This would serve to reduce server stress and increase browser response. Plus: there's no point loading what the visitor may never scroll to look at.
So the code in pseudo terms is something like:
How wide is the screen?
Make (screen-width divided by column-width) columns.
While we have new infodivs being created, add them to the columns.
Don't add them all to one column, but shared them out equally.
The end result is dynamically created divs of info of equal widths, but varying heights, being laid out in a columnized fashion. Their natural tendency is to be as high up their parent as possible, so they'll always be sitting just beneath the infodiv above them.
Since the columns have their display property set to inline, they'll tend to sit side by side where there is space for them. A caveat is that if the width of the column's parent is reduced (after the initial layout is created), the right-most column will be pushed below its fellow columns.
As for the PHP - That's another story :-)
I want my jqGrid to shrink and expand based on the number of rows it has. Let say it currently has 10 rows, the height of the jqGrid will shrink to 10 rows (so that no gaping empty rows is exposed).
If however there are too many rows, the height of the grid will expand to a maximum 'height' value and a scroll bar will appear.
That's built into the grid. You set height to 100%. There's a demo on this page if you go "Advanced -> Resizing.
Try:
jQuery(".ui-jqgrid-bdiv").css('height', jQuery("#bigset").css('height'));
In the jQGrid callback function loadComplete. #bigset is the id for the table I used. This worked perfectly for me.
I have faced the similar problem and none of the solutions worked perfectly for me.
Some work but then there is no scrollbar.
So here is what I have done:
jQuery("#grid").jqGrid('setGridHeight', Math.min(300,parseInt(jQuery(".ui-jqgrid-btable").css('height'))));
This code has to be placed in the loadComplete handler and then it works fine.
The first parameter of the Math.min is the desired height when there is enough data to fill in the list. NOTE that this same value has to be set as height for the grid.
This script choses the minimum of the actual height and the desired height of the grid.
So if there are not enough rows the grid height is shrinked, otherwise we always have the same height!
call the below function from afterInsertRow and when deleting a row:
function adjustHeight(grid, maxHeight){
var height = grid.height();
if (height>maxHeight)height = maxHeight;
grid.setGridHeight(height);
}
Though the height 100% worked fine in the demo, it didn't work for me. The grid became much bigger, maybe it tried to occupy the parent div's height. Amit's solution worked perfectly for me, thanks! (I'm new as a contributor here, and so need a higher 'reputation' to mark any votes up :) )
Here is a generic method I came up with based on Amit's solution. It will allow you to specify the max number of rows to display. It uses the grid's header height to calculate max height. It may need tweeking if your rows aren't the same height as your header. Hope it helps.
function resizeGridHeight(grid, maxRows) {
// this method will resize a grid's height based on the number of elements in the grid
// example method call: resizeGridHeight($("#XYZ"), 5)
// where XYZ is the id of the grid's table element
// DISCLAIMER: this method is not heavily tested, YMMV
// gview_XYZ is a div that contains the header and body divs
var gviewSelector = '#gview_' + grid.attr('id');
var headerSelector = gviewSelector + ' .ui-jqgrid-hdiv';
var bodySelector = gviewSelector + ' .ui-jqgrid-bdiv';
// use the header's height as a base for calculating the max height of the body
var headerHeight = parseInt($(headerSelector).css('height'));
var maxHeight = maxRows * headerHeight;
// grid.css('height') is updated by jqGrid whenever rows are added to the grid
var gridHeight = parseInt(grid.css('height'));
var height = Math.min(gridHeight, maxHeight);
$(bodySelector).css('height', height);
}
Add below code inside loadComplete function
var ids = grid.jqGrid('getDataIDs');
//setting height for grid to display 15 rows at a time
if (ids.length > 15) {
var rowHeight = $("#"+gridId +" tr").eq(1).height();
$("#"+gridId).jqGrid('setGridHeight', rowHeight * 15 , true);
} else {
//if rows are less than 15 then setting height to 100%
$("#"+gridId).jqGrid('setGridHeight', "100%", true);
}