How to calculate jqGrid header height - javascript

jqgrid header
may contain extra toolbar defined using
toolbar: [true, "top"],
contains navigation toolbar defined using
$grid.jqGrid('navButtonAdd', '#grid_toppager', {...
and contains search toolbar.
To resize grid to end of screen I'm looking for a way to calculate this header height
in window resize.
I tried code below but this sets grid height too big.
How to calculate grid header height ?
$(window).resize(function () {
var extraToolbarHeight = $('#t_' + $.jgrid.jqID($grid[0].id)).outerHeight(true),
caption_height=$("div#gview_"+$grid[0].id+" > div.ui-jqgrid-hdiv").outerHeight(true);
$('#grid1container').height($(window).height() - 18);
$grid.jqGrid('setGridHeight', $('#grid1container').height()-caption_height
-extraToolbarHeight );
});
<div id="grid1container" style="width: 100%; height: 100%">
<table id="grid">
</table>
</div>

Here is a function I wrote to resize my jqGrids to fit their container element. See if it fits your needs.
// resize a grid to fill the space of its container
// this will throw an error if you pass in a non-existant
// Parameters:
// grid - a reference to your grid
// container - a reference to your container, or the selector
// Usage:
// resizeGrid($('#gridXYZ'), '#largeGridDiv')
function resizeGrid(grid, container) {
if (typeof container == 'string') {
container = $(container);
}
if (container.length > 0) {
var headerHeight = $($('.ui-jqgrid-hdiv')[0]).height();
var newHeight = container.height() - headerHeight;
grid.jqGrid().setGridHeight(newHeight);
grid.jqGrid().setGridWidth(container.width());
} else {
throw ('Non-existant container passed to resizeGrid()');
}
}
// some other selectors that may help, again grid
var gviewSelector = '#gview_' + $('#gridXYZ').attr('id');
var headerSelector = gviewSelector + ' .ui-jqgrid-hdiv';
var bodySelector = gviewSelector + ' .ui-jqgrid-bdiv';

Related

Determine element is at bottom of viewport and add class to it?

need some help here. I need to determine when a certain element is at bottom position of the viewport and then to add fixed class to it. So on scroll down add class when element is at bottom 0 and remove class when i scroll back up.
$(window).scroll(function() {
var $el = $('.content-btn-row');
if ($($el).position().top + $($el).height()) {
console.log("bottom!");
$(".content-btn-row").addClass("fixed");
} else {
$(".scontent-btn-row").removeClass("fixed");
}
});
IMO we should take into account inner height of a window's content area (it can be different that window height) and check if document has been scrolled.
window.innerHeight - returns the inner height of a window's content area
window.pageYOffset - returns the pixels the current document has been scrolled (vertically) from the upper left corner of the window
If the element is below viewport at the beginning this code should be ok:
var elem = window.innerHeight + $($el).height(); //position of the element
var winScroll = window.innerHeight + window.pageYOffset; //viewport height + scroll
if (elem) >= (winScroll) {
console.log("bottom!");
$(".content-btn-row").addClass("fixed");
} else {
$(".scontent-btn-row").removeClass("fixed");
}
}
and it will be better to check if there is a class "fixed" with hasClass before we add or remove it.
Why are you comparing the variables by adding same constant values(window.innerHeight) to them?
var elem = $($el).height();
var winScroll = window.pageYOffset;
if (elem) >= (winScroll) {
console.log("bottom!");
$(".content-btn-row").addClass("fixed");
} else {
$(".scontent-btn-row").removeClass("fixed");
}}
By this way we can reduce some complexity and code

How to determine the height and width of HTML user input and tell gridster to fit accordingly?

I'm currently using Gridster.js (http://gridster.net/) in combination with CKEditor.
Once the user saves their content with CKEditor, this content is put into the widget. However the widgets do not automatically resize themselves to fit the content, and while the user is able to resize it themselves, it would be more convienient for the userbase to have it be done for them the moment they press save.
I have tried a few things, but none to any avail. I'm having trouble getting the size of the current content, and then resizing the gridster respectively.
In my code, I have two values to work with. the gridster element (widget), and the value that will be put into it (contents). I have to determine the height of the contents. Once this is done successfully, I will be able to determine if my code for getting the x and y values work.
My current code looks like this:
// Initialization of the gridster element.
// The base dimensions are relevant to understand how we
// calculate the multipliers, later on.
gridster = $(".gridster > ul").gridster({
widget_margins: [10, 10],
widget_base_dimensions: [100, 50],
draggable: {
handle: 'header'
},
resize: {
enabled: true,
max_size: [20, 10],
min_size: [2, 1]
}
}).data('gridster');
And (the relevant bits of) my JavaScript class that handles saving and resizing:
// Saves the content from CKEditor to the gridster widget
this.save = function (data) {
var lastContents = this.default_html + data + '</div>';
$(this.editor).removeClass('gs-w-new');
this.resize_widget(this.editor, lastContents);
$(this.editor).html(lastContents);
this.modal.modal('hide');
};
/* #TODO: resize_widget function */
// if the new content from ckeditor is larger than the
// original size of the widget, we need to make it larger.
this.resize_widget = function(widgetId, contents) {
var element = $('<div>')
.addClass('fake-div-gs-w-resize')
/*
.fake-div-gs-w-resize {
position: absolute;
display: none;
height: auto;
width: auto;
white-space: nowrap;
}
*/
.css('display', 'block')
.html(contents);
var widget = $(widgetId);
var elementWidth = $(element).width(), // I am expecting this to return the width of the content, but it returns 0.
elementHeight = $(element).height(), // As you might imagine, this also returns 0.
width = widget.width(),
height = widget.height();
$(element).css('display', 'none');
console.log(widgetId, widget, width, height, elementWidth, elementHeight);
// this code never gets past here, because element{Height,Width} returns 0.
if (elementHeight > height || elementWidth > width) {
var width_multiplier = 100, // data-x = 1 === width_multiplier px
height_multiplier = 50; // from "widget_base_dimensions: [100, 50],"
var x = Math.round(width / width_multiplier),
y = Math.round(height / height_multiplier),
eX = Math.ceil(elementWidth / width_multiplier),
eY = Math.ceil(elementHeight / height_multiplier);
console.log("setting to x:" + eX + ", y:" + eY + " with width:" + width + ", height:" + height);
if (eX >= x && eY >= y)
gridster.resize_widget(widget, eX, eY);
}
};
Whilst I am not completely confident in my logic for determining the sizes; the main focus of this question is with determining the size of the HTML contents, as what I gathered from other SO posts did not seem to help in my case.
You need to actually add the element to the DOM for the width() and height() functions to work. In your example, the element is not added to the document.
See this JS Fiddle as an example https://jsfiddle.net/y1yf1zzp/10/
I had the same challenge, i.e. dynamic content appearing inside the new tile caused an overflow and appeared outside the tile boundaries. We used the '.scrollHeight' of the tile contents in combination with Zartus' code:
var contentHeight = $widgit.firstChild.scrollHeight;
var tileHeight = $widgit.firstChild.clientHeight;

Jquery Position not honoring on first call

I am trying to make my autocomplete menu open above the input box if there is not enough space below the input box to display the menu. The code works fine except for on the initial render.
This means that it always displays at the bottom when:
1. Start searching
2. Click in the field and fire the search for the existing text in field
I have it output the position.my and position.at contents and they both are correct for "above" placement but it still displays below the input box.
I have the function called resize that is binded to window scroll and resize also. The moment you scroll the page, the menu gets positioned correctly. My suspect is that it is positioning before fully rendering.
Code
_renderMenu function hook
// Autocomplete _renderMenu function
$(autocomplete_object)._renderMenu = function( ul, item ) {
var that = this;
jQuery.each( items, function( index, item ) {
that._renderItemData( ul, item );
});
// Make sure the menu is now shown to calculate heights and etc (menu is now rendered, position rendering next)
jQuery(ul).show();
autocomplete.resize(ul, options);
autocomplete.create_dropdown_handlers(ul, options);
}
Resize Function
// Resize function
function resize( ul, options ) {
var height;
// If the height of the results is smaller than the space available, set the height to the results height
var ul_height = 0;
jQuery(ul).find('li').each(function(i, element){
ul_height += jQuery(element).height();
});
// Make the height the full height available below the input box but above the window cut off
// Move the dropdown above the input box if there is not enough room below the input box
var $parent = jQuery("#" + options.name);
var padding = 25; // arbitrary number to prevent dropdown from hitting the window border in either direction
var bottom_distance = autocomplete.getViewportHeight() - ($parent.offset().top + $parent.height()) - padding;
var bottom_limit = 200;
var ul_position = {
my: "left top",
at : "left bottom",
of: $parent,
collision: 'none'
};
height = bottom_distance;
if (bottom_distance < bottom_limit) {
var top_distance = $parent.offset().top - padding;
height = top_distance;
// ----- It is getting here fine! -----
ul_position.my = "left bottom";
ul_position.at = "left top";
}
// We have room to show the entire dropdown results without a scrollbar
if (ul_height < height) {
height = 'auto';
}
// Position below or above parent depending on space
jQuery(ul).position(ul_position);
jQuery(ul).css({height: height == 'auto' ? height : height + 'px'});
}
TLDR:
Jquery position is set to show above input field, but it still shows below?
I ended up having to update the autocomplete object's position value as well as the ul position. I believe the issue was that the initial render would inherit the autocomplete's position variable (Which defaults to showing below the input box).
Here is the new line:
// In the resize function after jQuery(ul).position(ul_position);
$parent.autocomplete("option", "position", ul_position); // Now the rendering is correct!
Resize function addition
function resize (ul, options) {
...
calculate the height and position requirements
...
jQuery(ul).position(ul_position);
$parent.autocomplete("option", "position", ul_position); // <-- Addition to honor position for rendering
}

group elements by rel attribute

I am using equalHeightColumns.js to provide a cross browser equal height, which works fine until I need to have 2 sets of equal height.
So at the moment I have:
$(".row").each(function(){
$(this).find(".equalHeight").equalHeightColumns();
});
<div class="row">
<section class="equalHeight"></section>
<section class="equalHeight"></section>
</div>
<div class="row">
<section class="equalHeight"></section>
<section class="equalHeight"></section>
</div>
As you can see I dont want everything with the equalHeight to have the same height only inside the same row.
The problem is that now I need to change the mark up and dont have the row to reference. Is it possible to make this work like the lightbox rel='group2' plugin so that I can group the equalHeight elements via attribute.
E.g: this would be
<section class="equalHeight" rel="group1"></section>
<section class="equalHeight" rel="group1"></section>
<section class="equalHeight" rel="group2"></section>
<section class="equalHeight" rel="group2"></section>
equalHeightColumns.js
/*!
* equalHeightColumns.js 1.0
*
* Copyright 2013, Paul Sprangers http://paulsprangers.com
* Released under the WTFPL license
* http://www.wtfpl.net
*
* Date: Thu Feb 21 20:11:00 2013 +0100
*/
(function($) {
$.fn.equalHeightColumns = function(options) {
defaults = {
minWidth: -1, // Won't resize unless window is wider than this value
maxWidth: 99999, // Won't resize unless window is narrower than this value
setHeightOn: 'min-height', // The CSS attribute on which the equal height is set. Usually height or min-height
heightMethod: 'outerHeight',// Height calculation method: height, innerHeight or outerHeight
delay: false,
delayCount: 100
};
var $this = $(this); // store the object
options = $.extend({}, defaults, options); // merge options
// Recalculate the distance to the top of the element to keep it centered
var resizeHeight = function(){
// Get window width
var windowWidth = $(window).width();
// Check to see if the current browser width falls within the set minWidth and maxWidth
if(options.minWidth < windowWidth && options.maxWidth > windowWidth){
var height = 0;
var highest = 0;
// Reset heights
$this.css( options.setHeightOn, 0 );
// Figure out the highest element
$this.each( function(){
height = $(this)[options.heightMethod]();
if( height > highest ){
highest = height;
}
} );
// Set that height on the element
$this.css( options.setHeightOn, highest );
} else {
// Add check so this doesn't have to happen everytime
$this.css( options.setHeightOn, 0 );
}
};
// Call once to set initially
if (options.delay){
setTimeout(resizeHeight, options.delayCount);
} else {
resizeHeight();
}
// Call on resize. Opera debounces their resize by default.
$(window).resize(resizeHeight);
};
})(jQuery);
If you want an automatic script, you need to do a recursive function like that :
var $all = $('.equalHeight'),
arrEqualH = [];
recursiveFilter()
function recursiveFilter(){
var attr = $all.first().attr('rel');
arrEqualH.push($('[rel='+attr+']'));
$all = $all.not('[rel='+attr+']');
if($all.length) recursiveFilter()
}
$.each(arrEqualH, function(){
this.equalHeightColumns();
})
Fiddle : http://jsfiddle.net/2w9tq/
You could try that:
$(".row").each(function(){
$(this).find(".equalHeight[rel='group1']").equalHeightColumns();
$(this).find(".equalHeight[rel='group2']").equalHeightColumns();
});

Dynamically change height of rows of Kendo Grid on container Kendo window resize

I have two issues. I have a grid on a page which is contained within a Kendo window. I need the size of the grid rows to increase/decrease to ensure it fills the whole height of the window. I also have a grid on a different page which is just inside a Div that needs to be resized to fit the height of its container on the document window resize.
I have the following code given to me by Kendo support, but it doesn't do what I need it to do. It only sets the grid to be 100% of its container. But this leaves white space underneath the rows. I want to have no white space and for the rows to dynamically change their height so they all fit within the space together for one of them, and dynamically change the pageSize after calculating how many rows would fit in the size of the window for the other.
One of the grids is a top ten grid and the other is a list of all employees grid.
$(window).resize(function() {
var gridElement = $("#grid"),
newHeight = gridElement.innerHeight(),
otherElements = gridElement.children().not(".k-grid-content"),
otherElementsHeight = 0;
otherElements.each(function(){
otherElementsHeight += $(this).outerHeight();
});
gridElement.children(".k-grid-content").height(newHeight - otherElementsHeight);
});
Apologies for the amount of text but I've been stuck on this for days and wanted to give you as much info as possible.
EDIT: horizontal resizing works as intended out of the box. Why is the height any different? :S
EDIT2: Here is the code im using for my grid, this resides in the kendo window's content section
#(Html.Kendo().Grid<DataModels.UI.OperatorPickRatesChartModel>()
.Name("topTenPickersChart")
.Columns(columns =>
{
columns.Bound(b => b.operatorId).Title("Operator Id");
columns.Bound(b => b.averagePicksLastThirty).Title(" Average Picks Last Thirty");
})
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Field(b => b.operatorId).Editable(false);
model.Field(b => b.averagePicksLastThirty).Editable(false);
})
.Read("operatorTopTenPickRates", "DashBoard")
.Events(events => events.Error("error"))
.PageSize(10)
)
.Filterable()
)
For the following solution you need to have the table inside an HTML element that uses 100% of the area (width and height). For getting it what I do is define the HTML as:
<div id="container">
<div id="grid"></div>
</div>
and the following CSS style:
#container {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
Not, once the window is resized we need to do some maths...
$(window).resize(function () {
// Get container height
var containerH = $("#container").height();
// Get Grid height
var tableH = grid.element.height();
// Get Grid body height (the remaining is header and footer)
var bodyH = grid.table.height();
// The new height of the body is:
grid.table.height(containerH - tableH + bodyH - 1);
});
JSFiddle showing it here: http://jsfiddle.net/OnaBai/dB5CF/
EDIT: If your grid is inside a kendo window, then you have to:
You don't need the CSS definition.
You are not resizing $(window) but kendoWindow so I will put that code inside Kendo Window resize event handler.
You need to set an initial width for Kendo Window.
So your code should be something like:
$("#container").kendoWindow({
width : 400,
resize: function (e) {
console.log("resize", e);
var containerH = $("#container").height();
var tableH = grid.element.height();
var bodyH = grid.table.height();
grid.table.height(containerH - tableH + bodyH - 1);
}
});
var grid = $("#grid").kendoGrid({
dataSource: {
data : createRandomData(100),
pageSize: 10,
schema : {
model: {
fields: {
Id : { type: 'number' },
FirstName: { type: 'string' },
LastName : { type: 'string' },
City : { type: 'string' }
}
}
}
},
editable : false,
pageable : true,
columns : [
{ field: "FirstName", width: 90, title: "First Name" },
{ field: "LastName", width: 90, title: "Last Name" },
{ field: "City", width: 100 }
]
}).data("kendoGrid");
And the modified JS Fiddle here: http://jsfiddle.net/OnaBai/dB5CF/2/

Categories