jQuery resizing code causing perpetual resize event in IE7 - javascript

This is a bit of JavaScript (jQuery) I wrote that shrinks an element to be as high as possible while still keeping the entire page above the fold. The way it works is essentially "calculate the height difference between the document and the window, and make the element smaller by that much". (see below.)
This works fine as far as I can tell — except that unfortunately I still need IE7 support, and the behavior in that browser is kind of wonky. Specifically, calling my function seems to fire another resize event, causing a kind of feedback loop.
IE7 is apparently the only browser this happens in, and I haven't yet figured out why it happens. I've already tried making the target height smaller to make sure nothing goes out of bounds, but the result is the same.
What's the best way to make my code not fire the resize event in IE7?
function stretchToBottom($element) {
(window.onresize = function () {
// temporarily reset the element's height so $(document).height() yields the right value
$element.css({maxHeight: ''});
var heightDiff = $(document).height() - $(window).height();
if (heightDiff <= 0) {
return;
}
var initialHeight = $element[0].scrollHeight;
var minHeight = 200;
var targetHeight = initialHeight - heightDiff;
var height = Math.max(targetHeight, minHeight);
$element.css({maxHeight: height + 'px'});
})();
}

wrap your code with:
<!--[if !IE7]>-->
//NONE IE code comes here
<!--<![endif]-->
<!--[if IE7]>
//ONLY IE7 code comes here
<![endif]-->
more info here

I just discovered this question which describes the exact same problem I have. The top two answers offered a working solution: store the current window dimensions and process the event listener only when they have actually changed.
For the record, here's the working code I currently have. I changed the function name to be more accurate and moved the "add event listener" part to outside the function.
function shrinkToFit($element) {
$element.css({maxHeight: ''});
var heightDiff = $(document).height() - $(window).height();
if (heightDiff <= 0) {
return;
}
var initialHeight = $element[0].scrollHeight;
var minHeight = 200;
var targetHeight = initialHeight - heightDiff;
var height = Math.max(targetHeight, minHeight);
$element.css({maxHeight: height + 'px'});
}
var lastWindowWidth = $(window).width();
var lastWindowHeight = $(window).height();
$(window).on('resize', function () {
if (lastWindowWidth !== $(window).width() || lastWindowHeight !== $(window).height()) {
shrinkToFit($tableContainer);
lastWindowWidth = $(window).width();
lastWindowHeight = $(window).height();
}
});

Related

Change height of element on resize

Hello guys I'm trying to change height of my element dynamically.
These are my variables.
var windowWidth = 1440;
var currentWidth = $(window).width();
var elementHeight = $('#line4').height();
Now what I want is when difference between window width and current width is lower then 6 I want to change height of my element. I want to do this every time when (windowWidth - currentWidth)<6. So every time when window resizes and it's lower then 6 I want to change height of element by minus 14px. This is what I've tried.
$( window ).bind("resize", function(){
if((windowWidth - currentWidth)<6) {
$("#line4").css('height', elementHeight-14);
}
});
It does not work and I don't know what I'm missing. Also follow up question can I change other CSS properties this way. For this particular problem I will also need to change css top property in the same way, because I have some div with absolute position.
You need to measure the current width of the window on every resize event, since it's changing too.
var windowWidth = 1440;
var currentWidth = $(window).width();
var elementHeight = $('#line4').height();
$( window ).bind("resize", function(){
currentWidth = $(window).width()
if((windowWidth - currentWidth)<6) {
$("#line4").css('height', elementHeight-14);
}
});
You need to get windowWidth each time resize event called
And you should add debounce into resize event for better performance.
I often do like this, maybe you can search any better way:
var resizeTimer;
$(window).on('resize', function(e) {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
// Run code here, resizing has "stopped"
currentWidth = $(window).width()
if((windowWidth - currentWidth)<6) {
$("#line4").css('height', elementHeight-14);
}
}, 250);
});
and I created this to test, you can try it. Btw i increase from 6 to 600 to check easier :D
https://codepen.io/huytran0605/pen/NgBEVO

jQuery width change detection

Now Solved, thanks
I have see a lot of near answers to my problem with resize(), here is my code:
'larger()' is a layout function that I want to call when screen width regardless of device orientation is >= 501, 'smaller()' is a function that i want to call when the screen width is < 501.
My problem I have is that I don't want these functions to be called when the window.height changes. Note that in my page I am using an accordion in mobile view and if I expand an accordion panel, it adds height to the page, even though the browser window hasn't been re-sized. jQuery sees this as a window.resize.
$(window).resize(function(e) {
var winWidth = $(window).width();
if (winWidth >= 501){
larger();
}
if (winWidth < 501){
smaller();
}
});
any answers appreciated, and let me know if I need to clarify anything.
I am using jquery-1.11.0.min.js with jquery-ui-1.10.3.custom.min.js
Thanks
How about storing a reference to the previous width and if the width has changed on resize then call your functions - otherwise skip it. Like So:
// If you don't want it to change the first time
// then set this value on document load to get initial window width
var prevWinWidth = 0;
$(window).resize(function(e) {
var winWidth = $(window).width();
if(winWidth != prevWinWidth) {
if (winWidth >= 501){
larger();
}
if (winWidth < 501){
smaller();
}
prevWinWidth = winWidth;
}
});
Create a global variable that keeps track of the last known width of the window. Only if the width is changing, evaluate the width to call the appropriate function.
var lastWidth = 0;
$(window).resize(function (e) {
var winWidth = $(window).width();
if (lastWidth !== winWidth) {
winWidth >= 501 ? larger() : smaller();
lastWidth = winWidth;
}
});

Content Height Based On Browser Viewport

I have some Javascript using JQuery to give my main content's container a height if it is smaller than the browser's viewport. This is to ensure the footer is always at the bottom of the page. Wen I call it like this, it works:
$(document).ready(function() {
var windowHeight = $(window).height();
var contentHeight = windowHeight - 325;
if($("#content").height() <= contentHeight) {
alert(contentHeight);
$("#content").height(contentHeight+"px");
}
});
But I want to declare it as a function so I can use it on the page resize event, but when I do that, it doesn't work. Here is the code I am trying to use:
function pageSizer() {
var windowHeight = $(window).height();
var contentHeight = windowHeight - 325;
if($("#content").height() <= contentHeight) {
alert(contentHeight);
$("#content").height(contentHeight+"px");
}
}
$(document).ready(pageSizer());
$(window).resize(pageSizer());
Any ideas?
$(document).ready(pageSizer());
$(window).resize(pageSizer());
change to
$(document).ready(pageSizer);
$(window).resize(pageSizer);
You are invoking your functions instead of passing them as a reference which jQuery expects.

window.resize for calculating a box

I have this js code:
$(window).resize(function() {
var formHeight = $(".box-demo").outerHeight() + 40;
$(".box-demo").css("top",-formHeight+"px");
});
When you resize the window. The box-demo is recalculating the height of the form. But now i have a problem with this on mobile devices.
Only when the change width. Then this function must be performed. Now it happened when the document changing the height and width. How can i make this. That is only performed when i changed the width of the document.
Thanks for helping!
There's possibly a better way of doing this, but you could base it on a preset window width value. Only if the width changes should the resizing occur:
var windowWidth;
$(document).ready(function() {
windowWidth = $(window).width();
})
$(window).resize(function() {
if($(this).width() != windowWidth)
{
var formHeight = $(".box-demo").outerHeight() + 40;
$(".box-demo").css("top",-formHeight+"px");
windowWidth = $(this).width();
}
});
Edit: You can also avoid having to append the "px" by using:
$(".box-demo").css({top: -formHeight});
Edit 2: If you want to make it change when only the width has changed, you could also add a height check as well:
var windowHeight;
...
if($(this).width() != windowWidth && $(this).height) == windowHeight)
Extract the the method, and bind it on document ready too.

window.resize event firing in Internet Explorer

As you are aware, in Internet Explorer, the window.resize event is fired when any element on the page is resized. It does not matter whether the page element is resized through assigning/changing its height or style attribute, by simply adding a child element to it, or whatever -- even though the element resizing does not affect the dimensions of the viewport itself.
In my application, this is causing a nasty recursion, since in my window.resize handler I am resizing some <li> elements, which in turn re-fires window.resize, etc. Again, this is only a problem in IE.
Is there any way to prevent window.resize from firing in IE in response to elements on the page being resized?
I should also mention that I'm using jQuery.
I just discovered another problem which might help you.
I am using jQuery and I have window.resize event to call a function which will re-position the div appended to the body.
Now when I set the LEFT css property of that appended div, the window.resize event get trigger for NO GOOD REASON.
It results in an infinite loop, triggering the window.resize again and again.
The code without fix:
$(window).resize(function(){
var onResize = function(){
//The method which alter some css properties triggers
//window.resize again and it ends in an infinite loop
someMethod();
}
window.clearTimeout(resizeTimeout);
resizeTimeout = window.setTimeout(onResize, 10);
});
Solution:
var winWidth = $(window).width(),
winHeight = $(window).height();
$(window).resize(function(){
var onResize = function(){
//The method which alter some css properties triggers
//window.resize again and it ends in an infinite loop
someMethod();
}
//New height and width
var winNewWidth = $(window).width(),
winNewHeight = $(window).height();
// compare the new height and width with old one
if(winWidth!=winNewWidth || winHeight!=winNewHeight){
window.clearTimeout(resizeTimeout);
resizeTimeout = window.setTimeout(onResize, 10);
}
//Update the width and height
winWidth = winNewWidth;
winHeight = winNewHeight;
});
So basically it will check if the height or width is changed (which will happen ONLY when you actually resize with window).
this made sense to me and seems to work in IE7 and above:
//variables to confirm window height and width
var lastWindowHeight = $(window).height();
var lastWindowWidth = $(window).width();
$(window).resize(function() {
//confirm window was actually resized
if($(window).height()!=lastWindowHeight || $(window).width()!=lastWindowWidth){
//set this windows size
lastWindowHeight = $(window).height();
lastWindowWidth = $(window).width();
//call my function
myfunction();
}
});
Bind your resize listener with .one() so that it unbinds itself after firing. Then you can do anything you want, so long as at the end you rebind the resize listener. I found the easiest way to do this is by putting the resize listener in an anonymous function like so:
var resizeListener = function(){
$(window).one("resize",function(){ //unbinds itself every time it fires
//resize things
setTimeout(resizeListener,100); //rebinds itself after 100ms
});
}
resizeListener();
You don't technically need the setTimeout wrapped around the resizeListener() but I'd threw it in there as a just-in-case and for some extra throttling.
I solved it by unbinding the resize function, rebuilding the page and then binding the resize function again:
function rebuild() {
$(window).unbind('resize');
/* do stuff here */
$(window).bind('resize',rebuild);
}
$(window).bind('resize',rebuild);
EDIT
Bind and unbind don't go well with IE8. Though Microsoft even gave up on IE8 you might want to try this (untested!):
function rebuild(){
if(!window.resizing) return false;
window.resizing=true;
/* do stuff here */
window.resizing=false;
}
window.resizing=false;
document.body.onresize=rebuild;
#AamirAfridi.com's answer solved my problem.
It's a good idea to write a common function to solve such stuff:
function onWindowResize(callback) {
var width = $(window).width(),
height = $(window).height();
$(window).resize(function() {
var newWidth = $(window).width(),
newHeight = $(window).height();
if (newWidth !== width || newHeight !== height) {
width = newWidth;
height = newHeight;
callback();
}
});
}
Use it like this, and you don't have to worry about the different behavior in IE any more:
onWindowResize(function() {
// do something
});
I ran into this problem today and decided to put the following at the top of my global included javascript file:
var savedHeight = 0;
var savedWidth = 0;
Event.observe(window, 'resize', function (e) {
if (window.innerHeight == savedHeight &&
window.innerWidth == savedWidth) { e.stop(); }
savedHeight = window.innerHeight;
savedWidth = window.innerWidth;
});
That requires Prototype, by the way.
A mix of the unbind / bind method with a delayed call.
It works in Internet Explorer 8 and below, preventing evil loop and hangs on versions 6 and 7.
function resizeViewport()
{
// Unbind and rebind only for IE < 9
var isOldIE = document.all && !document.getElementsByClassName;
if( isOldIE )
$(window).unbind( 'resize', resizeViewport );
// ...
if( isOldIE )
{
setTimeout(function(){
$(window).resize( resizeViewport );
}, 100);
}
}
$(window).resize( resizeViewport );
You can try this:
Constructor:
this.clientWidth = null;
this.clientHeight = null;
Some function:
var clientWidth = window.innerWidth || document.documentElement.clientWidth;
var clientHeight = window.innerHeight || document.documentElement.clientHeight;
if (clientWidth != this.clientWidth || clientHeight != this.clientHeight ) {
this.clientWidth = clientWidth;
this.clientHeight = clientHeight;
... YOUR CODE ...
}
For Internet Explorer, Chrome, Firefox, Opera, and Safari:
window.innerHeight - the inner height of the browser window
window.innerWidth - the inner width of the browser window
For Internet Explorer 8, 7, 6, 5:
document.documentElement.clientHeight
document.documentElement.clientWidth
or
document.body.clientHeight
document.body.clientWidth
(function ($){
//if ie8 -> return;
var lastHeight = 0;
var lastWidth = 0;
$(window).resize(function(event){
if (window.innerHeight == lastHeight && window.innerWidth == lastWidth)
{ event.stopImmediatePropagation(); }
lastHeight = window.innerHeight;
lastHeight = window.innerWidth;
});
})();
does the trick for me...
<pre>
var cont = 0;
var tmRsize = 100;
var lastWindowWidth = $(window).width();
var lastWindowHeight = $(window).height();
/*****redimensionamiento**********/
$(window).resize(function()
{
if($(window).width() != lastWindowWidth || $(window).height() != lastWindowHeight)
{
clearTimeout(this.id);
this.tiempo = tmRsize;
this.id = setTimeout(doResize, this.tiempo);
}
});
function doResize()
{
lastWindowWidth = $(window).width();
lastWindowHeight = $(window).height();
$('#destino_1').html(cont++);
}
Here's how i deal with finding out if the resize event was fired by an element or by really resizing the window:
If the event's target.nodeType doesn't exist, it is most likely the window, as any other element on the page would have a nodeType.
So here's the pseudo-code (using jQuery) with the added check:
$(window).resize(function(event){
if ( $(event.target.nodeType).length == 0 ){
// Anything here is run when the window was resized
// not executed when an element triggered the resize
}
});
I couldn't get the resize event to fire when an element resized (only tried in IE8 though).
However what is the target on the event object when you're experiencing this issue, could you do:
$(window).resize(function(e) {
if( e.target != window ) return;
// your stuff here
});
My patch:
<!--[if lte IE 7]>
<script type="text/javascript">
window.onresize = null; // patch to prevent infinite loop in IE6 and IE7
</script>
<![endif]-->
It is up to the how contents are on the resize event.
I figured out the above solves only when a page consists of static contents, not dynamically rendered ones.
In the dynamic case where the existing contents will be re-rendered by some trigger event like a contents reload function, we need to use $(document).width() or $(document).height() instead.
This is because of scroll bar of the window.
If a page has the scroll bar and the main contents will be re-rendered by clicking a button “Reload”, the scroll bar disappears on the event.
In that case, $(window).width() or $(window).height() is changed by the contents rendering, not by the actual window resizing.
$(window).resize(function(event)
{
if (typeof event.target.tagName == 'undefined')
{
// ...
}
});

Categories

Resources