There are plenty of examples showing how to dynamically set an iframe's height to its content. This works perfect for me. The problem I'm now having is that the content can change size without triggering onload (think hidden/expandable divs).
Is there any way to detect when the size of the iframe content has changed? This is on the same domain and no jQuery, please.
I would do this by polling regularly (maybe every 200 milliseconds, perhaps more often) using setInterval. You could then compare the size of the content to what it was last time.
var iframe = document.getElementById('myIframe'),
lastheight;
setInterval(function(){
if (iframe.document.body.scrollheight != lastheight) {
// adjust the iframe's size
lastheight = iframe.document.body.scrollheight;
}
}, 200);
For non-webkit browsers, there are a few domMutation-Events, that fire when an attribute of an element (e.g. the body element) change. See DOMSubtreeModified and more importantly DOMAttrModified.
The internet explorer does fire the onresize event even on non-windows elements.
Opera honors the domMutation Events.
Webkit on the other discarded these events as a compromise to rendering speed and javascript-performance. Thee is no other way than to check via timeout/interval the effective size of an element.
ResizeObserver worked for me:
const iframe = document.getElementById('myIframe')
const observer = new ResizeObserver(() => {
setHeight(iframe.document.body.scrollHeight);
})
observer.observe(iframe.document.body);
Related
I often find that if I create or reparent DOM nodes in javascript, the CSS engine doesn't recalculate the sizes of the parent containers. This happens in Firefox and Chrome.
For example, the body might stay the same size while new content overflows the bottom. If I resize the window the body grows, but it doesn't "lock in" to its correct size until the window is sized to be at least as big as the body should be.
Is there a way to trigger a full layout recomputation in Javascript?
I can able to trigger CSS Engine via:
document.body.style.zoom = 1.0000001;
setTimeout(function(){document.body.style.zoom = 1;},50); //allow some time to flush the css buffer.
For every time after resizing the window use the following:
$(window).resize(function() {
if(this.resizeTO) clearTimeout(this.resizeTO);
this.resizeTO = setTimeout(function() {
$(this).trigger('resizeEnd');
}, 500);
});
$(window).bind('resizeEnd', function() {
document.body.style.zoom = 1.0000001;
setTimeout(function(){document.body.style.zoom = 1;},50);
});
You can trigger a repaint from JavaScript by setting a CSS style to an innocuous value, e.g.
document.body.style.zIndex = 1;
Yes. I tend to put a random className on the <html> element, using:
document.documentElement.className = 'reflow_' + (new Date()).getTime();
which creates:
<html class="reflow_1483757400611">
Tried and tested on everything from Android Browser 4 to Smart TV's via camposat.tv
The browser does recompute the geometry of all elements after DOM manipulation. One likely reason you might see an element "stuck" at a certain height even after its content has changed is this CSS rule:
body { height: 100% };
It tells the browser, make the body element as large in height as the viewport regardless of its content.
Try changing it to:
body { min-height: 100% };
This will tell the browser to make body at least as large in height as the viewport or larger if there is more content.
The CSS3 resize property can be assigned to arbitrary elements. I'm looking for a way to detect such a resize on, say, divs (I don't mind it only working in Firefox at the moment):
div {
resize: horizontal;
overflow: hidden;
}
Unfortunately, the onresize event seems not to be fired on the div. How can I detect in JavaScript when such a user-instantiated resize has happened?
Edit: FWIW I had opened a bug report over at Mozilla. If you want to track it: https://bugzilla.mozilla.org/show_bug.cgi?id=701648
Resizing is like a style change. As such it can be observed with a MutationObserver. The more specific ResizeObserver is probably even better:
let observer = new ResizeObserver(function(mutations) {
console.log('mutations:', mutations);
});
let child = document.querySelector('textarea');
observer.observe(child, { attributes: true });
<textarea></textarea>
Listen to DOMAttrModified events. Got the idea from this answer, this jsFiddle appears to work in Firefox 8 (if you open the console).
Since the resize event clearly doesn't work (currently, at least), you can try one of these alternative options:
Use a combination of mousedown, mousemove and/or mouseup to tell whether the div is being / has been resized. If you want really fine-grained control you can check in every mousemove event how much / if the div has been resized. If you don't need that, you can simply not use mousemove at all and just measure the div in mousedown and mouseup and figure out if it was resized in the latter.
Poll every 200ms or so (depending on your needs) and compare the current size with the last known size. See setTimeout().
You can use the ResizeSensor class of the css-element-queries polyfill from
https://github.com/marcj/css-element-queries
It allows you to call a javascript function on size changes for all types of elements, not only for window. It sets up a real sensor, not a javascript setTimeout poll.
Use it like this:
new ResizeSensor($('#myelement'), function() {
console.log("myelement's size has changed");
});
Supported browsers are: all incl. IE6+.
This seemed to work pretty well for me:
$("body").on('mousedown mousemove', ".resizeItem", function () {
console.log($(this).height());
})
"Use a combination of mousedown, mousemove and/or mouseup"
as per Felixs answer.
Especially useful when combining a custom search result panel with Dev Extremes Scroll View and you want full control over it.
$("body").on('mousedown mousemove', ".scrollContainer", function () {
var h = $(this).height() - 20;
$(".scrollArea").dxScrollView('instance').option('height', h);
});
According to this site it only works in internet explorer 9.
Try this fiddle: http://jsfiddle.net/maniator/3Zva3/
so suppose that clicking something would lead to a new content being loaded to the screen hence the height of document changes and whereas previously there are no scroll bars, now there actually are scrollbars...
how do I detect something like that happening using jquery
binding resize event onto window only detects window resize whereas binding it into document doesn't work
Update:
Please don't use the DOMSubtreeModified event. It is old, deprecated and not well-supported by browsers. In 99,9 % of the cases, there is a different event you can listen on. Most likely you are one of those people using jQuery and doing some AJAX stuff, so please take a look at their AJAX docs.
These are all available events. You would have to detect $(document).bind('DOMSubtreeModified', function() { ... }); and check for a dimension change to the previous firing.
var height = $(this).height(),
width = $(this).width();
$(document).bind('DOMSubtreeModified', function() {
if($(this).height() != height || $(this).width() != width) {
recalibrate();
}
});
This event is firing every time anything is done to the DOM. Therefore it will slowdown your browser.
We should get a better alternative. Could you please give us more information to your scenario?
Here is the solution.
// ajdust margins when page size changes (ie rotate mobile device)
$(window).resize(function() {
// Do something more useful
console.log('doc height is ' + $(window).height());
});
You could try a percentage scrolled event like this one:
http://www.jquery4u.com/snippets/jquery-detect-scrolled-page/
You might need to add a check to see whether the vertical scrollbar is present:
var hasVScroll = document.body.scrollHeight > document.body.clientHeight;
We are using Mootools Multibox to display images.
The first time we view it with Chrome and Safari, the images are zoomed in and have scrollbars.
When we reload the page, the images display correctly without scrollbars.
What could be the cause of this?
How can we fix this so that the images are displayed with their correct sizes the first time viewed in Chrome and Safari?
in this block of code:
showContent: function(){
this.box.removeClass('MultiBoxLoading');
this.removeContent();
this.contentContainer = new Element('div', {
'id': 'MultiBoxContentContainer',
'styles': {
opacity: 0,
width: this.contentObj.width,
height: (Number(this.contentObj.height)+this.contentObj.xH)
}
}).inject(this.box,'inside');
it sets with width of the content box to the contentObj.width direct. which is fine if the browser has the image in the cache - at which point it will work but not so fine when it does not.
it uses Asset.js to load an image here:
load: function(element){
this.box.addClass('MultiBoxLoading');
this.getContent(element);
if(this.type == 'image'){
var xH = this.contentObj.xH;
this.contentObj = new Asset.image(element.href,{onload:this.resize.bind(this)});
this.contentObj.xH = xH;
}else{
this.resize();
};
},
the problem is, only after the onload fires does the browser know the actual width and height of the image (available through this.width / this.height if not bonund to class scope). although this will return an image object early (into contentObj), it probably shouldn't just yet and should do it after the onload fires. the onload here should be what injects the image into the container and sets width and height to host it. instead, it applies this.resize(image)
i hope this gives you some ideas as to how to refactor the class to make it work better.
ADDITONALLY: var xH = this.contentObj.xH; and this.contentObj.xH = xH; -> element storage for other elements direct into the object? this pre-dates mootools 1.2 which introduced closure based uid specific storage per element. bad practice, can cause slowness in IE, memory leaks etc.
refactor to this.contentObj.store("xH", something) with this.contentObj.retrieve("xH") to get it back
I'm trying to resize an html element (flash object) but it doesn't seem to respond more than once per second?
Is this a limitation imposed by browsers (both IE7 and FF3 do this)?
Or should I be attempting to resize in a different/more efficient way?
function setHeightNow(height) {
if (document.getElementById) {
if (height > 0) {
var scaleItem = document.getElementById('application');
scaleItem.style.height = height + 'px';
}
}
}
If you are calling this function in a loop, as bobince mentioned in his/her comment, you should change it to a series of setTimeout calls (or setInterval) to give control back to the browser.
Something like this-
var i = INITIAL_VALUE;
(function() {
setHeightNow(foo);
if (i < FINAL_VALUE) {
i++;
setTimeout(arguments.callee, 0); //you can play around with the timeout.
}
})();
Also
The documents.getElementById check is kind of useless because all browsers support it.
It would be wise to somehow take the document.getElementById call outside this repeating function if possible.
It's certainly not a defined limitation; we run an animation loop that is triggered 30 times/sec. (Using a 33ms timeout.) Mostly we move backgrounds around (animations) or adjust opacity (fade in/out) but sometimes we also re-size elements.
However, all of those elements are absolutely positioned, or in a fixed container, so it doesn't trigger a re-layout by the browser. I suspect your problem is simply the cost of performing that re-layout, most of which would be down to the flash object itself.