How to clear these intervals? - javascript

I'm creating my own JSFiddle-like webapp and I want to implement elements resizing, but keep document height unchanged, so I have to recalculate elements dimensions on each resize.
I have this script:
var a = setInterval(setHeight, 1);
var b = setInterval(formsWidth, 1);
iframe.onResizeStart = a;
html.onResizeStart = b;
iframe.onResizeStop = clearInterval(a);
html.onResizeStop = clearInterval(b);
Iframe is an element where user codes are rendered and HTML is one of my three textareas. I want this script to recalculate textareas heights on iframe resize and recalculate their widths on changing width of one of them.
I managed to make this work, but I couldn't stop intervals and I need help with it.
The above code doesn't work now at all, probably because of calling a variable onResizeStart.
I'd be grateful if someone could help me.
I prefer not to use jQuery.

It doesn't work because you're calling clearInterval() almost immediately after calling setInterval(), so the intervals are never getting a chance to execute. You'll need to store away a and b and then call clearInterval() on them at a later time, after the resizing is all done.
EDIT: Looking at this more closely, just wrap each call to clearInterval() in a function. That way clearInterval won't get executed immediately, but rather when the onResizeStop event is fired.
iframe.onResizeStop = function() { clearInterval(a); };

Related

How to know if an element is rendered?

My element has transition: transform .5s
then it has a separate class: transform: translatex(-100%)
So what I would like to achieve is that initially, the element is positioned towards the left. At window onload,When the element is rendered, I remove the transform class, and the browser would animate the element back to its correct position.
But what actually happens is that when the page becomes visible/rendered, the element is already at the correct position. and there is no animation.
I tried setTimeout(function() {}, 0); it doesn't work. If I setTimeout for 1 second, it works, but sometime rendering takes long, and I have to setTimeout for 2 seconds. But then sometimes it renders fast, and 2 seconds is a long time to wait.
So overall, I feel this is not a reliable or a correct way of doing this.
How can I achieve what I want, the correct way?
Edit:
Sorry guys, after trying to put together a demo, I realized I wasn't removing the class at window onload. This is because my element and its javascript and css are loaded with AJAX. So it can happen before the window onload or after the window onload.
Anyway, now my question is, what if the window takes a long time to load? Could it be possible that my element would be rendered before window finishes loading? Or does browsers only render when the entire window finishes loadings?
Because I want to animate the element as soon as possible. So, is it safe to wait for window onload, in the case that window takes a long time to load(images and slow connection, and stuff)?
And if I load the element with AJAX after the window loads, could I immediately run the animation by removing the transform? Or should I detect for when the element is rendered?
You might want to try using a combination of the DOMContentLoaded event and requestAnimationFrame. DOMContentLoaded fires after the document has been completely loaded and parsed but before all of the images and other assets on the page have completed downloading. requestAnimationFrame will delay the removal of the class until after the page has been painted so the element will properly transition.
var box = document.getElementById('box'),
showBox = function (){
box.classList.remove('offscreen');
};
document.addEventListener("DOMContentLoaded", function(event) {
window.requestAnimationFrame(showBox);
});
jsfiddle
You should use DOM Content Loaded event of javascript
document.addEventListener("DOMContentLoaded", function(event) {
console.log("DOM fully loaded and parsed");
});
This will be fired only when your entire content is loaded and parsed fully by your browser.
Don't consider this an answer as I am sure you can find something more elegant, but this may give you some ideas.
Add this to the javascript AJAXed in - be sure to wrap the javascript in a document.ready:
$(function(){
var giveup = 0; //in case something goes wrong
var amirendered = 0;
while (amirendered==0){
setTimeout(function(){
if (element.length){
amirendered = 1;
$('#myElement').addClass(doTransition);
}
},200);
giveup++;
if (giveup>200) amirendered++; //prevent endless loop
}
}); //END document.ready

Javascript: Changing "document.body.onresize" does not take hold without "console.log"

I'm writing a website with a canvas in it. The website has a script that runs successfully on every refresh except for a line at the end. When the script ends with:
document.body.onresize = function() {viewport.resizeCanvas()}
"document.body.onresize" is unchanged. (I double-checked in Chrome's javascript console: Entering "document.body.onresize" returns "undefined".)
However, when the script ends with:
document.body.onresize = function() {viewport.resizeCanvas()}
console.log(document.body.onresize)
"document.body.onresize" does change. The function works exactly as it should.
I can't explain why these two functionally identical pieces of code have different results. Can anyone help?
Edit: As far as I can tell, "document.body" is referring to the correct "document.body". When I call console.log(document.body) just before I assign document.body.onresize, the correct HTML is printed.
Edit 2: A solution (sort of)
When I substituted "window" for "document" the viewport's "resizeCanvas" function was called without fail every time I resized the window.
Why does "window" work while "document" only works if you call "console.log" first? Not a clue.
Resize events: no go
Most browsers don't support resize events on anything other than the window object. According to this page, only Opera supported detecting resizing documents. You can use the test page to quickly test it in multiple browsers. Another source that mentions a resize event on the body element specifically also notes that it doesn't work. If we look at these bug reports for Internet Explorer, we find out that having a resize event fire on arbitrary elements was an Internet Explorer-only feature, since removed.
Object.observe: maybe in the future
A more general method of figuring out changes to properties has been proposed and will most likely be implemented cross-browser: Object.observe(). You can observe any property for changes and run a function when that happens. This way, you can observe the element and when any property changes, such as clientWidth or clientHeight, you will get notified. It currently works only in Chrome with the experimental Javascript flag turned on. Plus, it is buggy. I could only get Chrome to notify me about properties that were changed inside Javascript, not properties that were changed by the browser. Experimental stuff; may or may not work in the future.
Current solution
Currently, you will have to do dirty checking: assign the value of the property that you want to watch to a variable and then check whether it has changed every 100 ms. For example, if you have the following HTML on a page:
<span id="editableSpan" contentEditable>Change me!</span>
And this script:
window.onload = function() {
function watch(obj, prop, func) {
var oldVal = null;
setInterval(function() {
var newVal = obj[prop];
if(oldVal != newVal) {
var oldValArg = oldVal;
oldVal = newVal;
func(newVal, oldValArg);
}
}, 100);
}
var span = document.querySelector('#editableSpan');
// add a watch on the offsetWidth property of the span element
watch(span, "offsetWidth", function(newVal, oldVal) {
console.log("width changed", oldVal, newVal);
});
}
This works similarly to Object.observe and for example the watch function in the AngularJS framework. It's not perfect, because with many such checks you will have a lot of code running every 100 ms. Additionally any action will be delayed 100 ms. You could possibly improve on this by using requestAnimationFrame instead of setInterval. That way, an update will be noticed whenever the browser redraws your webpage.
What you can do is that if you know for certain what particular action triggers a resize on your element that doesn't resize the full window you can trigger a resize event so your browser recalculate all of the divs (if by the case the browser is not triggering the event correctly).
With Jquery:
$(window).trigger('resize');
In the other hand, if you have an action that resizes an element you can always hold from that action to handle other following logic.
<script>
function body_OnResize() {
alert('resize');
}
</script>
<body onresize="body_OnResize()"></body>

jQuery/JavaScript wait for page to load, but no shorter than specified time

I'm having the following issue:
I want to display an overlay until the page loads completely, which works just fine.
The problem is that on fast connections the overlay would disappear immediately, which is not what I want to achieve.
I was trying to do it the following way:
$(document).ready(function(){
setTimeout(function(){
$(window).load(function(){
$('#overlay').fadeOut(1200);
});
},1500);
});
which seemed logical to me. Didn't work. I replaced setTimeout with setInterval, didn't work, too. I put the $(window).load...etc. in a function and called it with an external setTimeout, no success. The best result in regard to that additional timer was, that browsers ignored it altogether; most of the time the overlay just stays there, nothing happens.
What am I missing?
You certainly don't need $(window).load... within the setTimeout function. In fact, putting it within the timeout will ensure that it never executes since the window.load event will have already fired before you assign it your function to fadeOut the overlay.
I've adjusted my code based on your feedback. The basic principle is to determine how long it took to get everything ready and then reduce the timeout based on the time already elapsed. This way your fastest connections will still get a delay while your slowest connections will execute the fadeout immediately.
Live Demo
//Put this line in a script tag as high up on the page as possible
window.timeInMs = Date.now();
Instead of document.ready which executes after the document is loaded, use window.load which executes after the entire page has loaded (frames, objects, images) - src.
$(window).load(function(){
var maxTimeout = 1500;//Everyone waits at least this amount, including fast browsers.
//Compute the elapsed time, default to 0 if more than maxTimeout has elapsed.
var remainingTime = Math.max(maxTimeout - (Date.now() - window.timeInMs), 0);
setTimeout(function(){
$('#overlay').fadeOut(1200);
}, remainingTime);
});

Scrolling Iframe

I have two windows: One is a page meant to be in an iframe, and one is the page meant to house the iframe. The objective of my project is to make an iframe that scrolls, but, when it is moused over, it pauses. I currently have the following code for the page meant to be in an iframe:
http://dabbler.org/edit/asdf/scrolling/index.html
and the code for the page meant to house the iframe:
http://dabbler.org/edit/asdf/scrolling/index2.html
What is wrong with my code? (Yes, I know I don't have body, head, HTML and the others, that isn't the problem, for those are thrust in automatically when the page is interpreted)
The window.onmouseover and window.onmouseout are not defined correctly.
You have this:
window.onmouseout = pageScroll();
window.onmouseover = unpageScroll();
You want to do this:
window.onmouseout = pageScroll;
window.onmouseover = unpageScroll;
You were setting onmouseout, and onmouseover to the return values of calling pageScroll and unpageScroll, but you wanted to set onmouseout/onmouseover the functions pageScroll and unpageScroll.
And finally, you're calling the wrong function in your setTimeout.
You are calling pageScroll, but you want to be calling pageScroller, which does the actual scrolling.
EDIT
function pageScroll(){
num = 150;
clearTimeout(scrolldelay);
pageScroller();
}
function unpageScroll(){num = 15000000;}
function pageScroller() {
window.scrollBy(0,50); // horizontal and vertical scroll increments
scrolldelay = setTimeout('pageScroller()',num); // scrolls every 100 millisecond
}
var num = 50;
window.onmouseout = pageScroll;
window.onmouseover = unpageScroll;
BTW, you should handle calling clearTimeout in pageScroller at some point in the future when the page is scrolled vertically as much as possible. There's no point in continuing to call scrollBy if the window is already scrolled as much as possible.

Why is the resize event constantly firing when I assign it a handler with a timeout?

I assigned a timeout to my window.resize handler so that I wouldn't call my sizable amount resize code every time the resize event fires. My code looks like this:
<script>
function init() {
var hasTimedOut = false;
var resizeHandler = function() {
// do stuff
return false;
};
window.onresize = function() {
if (hasTimedOut !== false) {
clearTimeout(hasTimedOut);
}
hasTimedOut = setTimeout(resizeHandler, 100); // 100 milliseconds
};
}
</script>
<body onload="init();">
...
etc...
In IE7 (and possibly other versions) it appears that when you do this the resize event will constantly fire. More accurately, it will fire after every timeout duration -- 100 milliseconds in this case.
Any ideas why or how to stop this behavior? I'd really rather not call my resize code for every resize event that fires in a single resizing, but this is worse.
In your //do stuff code, do you manipulate any of the top,left,width,height,border,margin or padding properties?
You may unintentionally be triggering recursion which unintentionally triggers recursion which unintentionally triggers recursion...
How to fix the resize event in IE
also, see the answer for "scunliffe" "In your ... properties?
IE does indeed constantly fire its resize event while resizing is taking place (which you must know, as you are already implementing a timeout for a fix).
I am able to replicate the results you are seeing, using your code, on my test page.
However, the problem goes away if I increase the timeout to 1000 instead of 100. You may want to try with different wait values to see what works for you.
Here is the test page I used: it has a nicely dynamic wait period already set up for you to play with.
I stumbled on the same problem, but solved it differenly, and I think it's more elegant than making a timeout....
The context: I have an iframed page, loaded inside the parent page, and the iframe must notify the parent when its size changes, so the parent can resize the iframe accordingly - achieving dynamic resizing of an iframe.
So, in the iframed HTML document, I tried to register a callback on the body tag. First, on the onchange - it didn't work. Then on resize - it did work, but kept firing constantly. (Later on I found the cause - it was apparently a bug in Firefox, which tried to widen my page to infinity). I tried the ResizeObserver - for no avail, the same thing happened.
The solution I implemented was this:
<body onload="docResizePipe()">
<script>
var v = 0;
const docResizeObserver = new ResizeObserver(() => {
docResizePipe();
});
docResizeObserver.observe(document.querySelector("body"));
function docResizePipe() {
v += 1;
if (v > 5) {
return;
}
var w = document.body.scrollWidth;
var h = document.body.scrollHeight;
window.parent.postMessage([w,h], "*");
}
setInterval(function() {
v -= 1;
if (v < 0) {
v = 0;
}
}, 300);
</script>
So how it works: each time the callback fires, we increment a variable v; once in every 300 ms, we decrement it; if it's too big, the the firing is blocked.
The big advantage of this over the timeout-based solution, is that it introduces to lag for a user experience, and also clear in how exactly it does block the recursion. (Well, actually not )))

Categories

Resources