Dynamically Resizing an Iframe - javascript

I can see that this question has been asked several times, but none of the proposed solutions seem to work for the site I am building, so I am reopening the thread. I am attempting to size an iframe based on the height of it's content. Both the page that contains the iframe and it's source page exist on the same domain.
I have tried the proposed solutions in each of the following threads:
Resize iframe height according to content height in it
Resizing an iframe based on content
I believe that the solutions above are not working because of when the reference to body.clientHeight is made, the browser has not actually determined the height of the document.
Here is the code I am using:
var ifmBlue = document.getElementById("ifmBlue");
ifmBlue.onload = resizeIframe;
function resizeIframe()
{
var ifmBlue = document.getElementById("ifmBluePill");
var ifmDiv = ifmBlue.contentDocument.getElementById("main");
var height = ifmDiv.clientHeight;
ifmBlue.style.height = (ifmBlue.contentDocument.body.scrollHeight || ifmBlue.contentDocument.body.offsetHeight || ifmBlue.contentDocument.body.parentNode.clientHeight || height || 500) + 5 + 'px';
}
If I debug the script using fire debug, the client height of the iframe.contentDocument's main div is 0. Additionally, body.offsetHieght, & body.scrollHeight are 0. However, after the script is finished running, if I inspect the DOM of the HTML iframe element (using fire debug) I can see that the body's clientHeight is 456 and the inner div's clientHeight is 742. This leads me to believe that these values are not yet set when iframe.onload is fired. So, per one of the threads above, I moved the code into the body.onload event handler of the iframe's source page. This solution also did not work.
Any help you can provide is much appreciated.
Thanks,
CJ

DynamicDrive has such a script, which I think does what you're asking for.
There's also a newer version now.
2011 update:
I would strongly recommend using AJAX over something like this, especially considering that a dynamically resizing iframe only works across the same domain.
Even so, it's a bit iffy, so if you absolutely must use AJAX over standard page loading, you really, really should use things like history.pushState (and have standard page loading as a fallback for browsers that don't support it). There's a jQuery plugin which handles this stuff for you, written by a GitHubber, called pjax, which they use only for repo navigation.

you moved the handler? maybe you should move the function to the inner frame as well, so that when you grab height values you reference the body directly rather than frame object... then call a parent.set height function
another trick, call function after settimeout of 10 msecs
i remember I had that problem once but I used IE's getBoundingClientRect() to get height of content, check mozilla developer center for something similar, this is just a hint, i did not research it
on another note, what is ifmBluePill? is it the iframe? or a div inside of it? why do you reference "contentDocument" of a div?

By the way, DynamicDrive improved their script to always resize even if the iframe contents change: http://www.dynamicdrive.com/dynamicindex17/iframessi2.htm
From their page:
This is version II of the original
Iframe SSI script, which like the
original script lets you seamlessly
display external content on your page
via an IFRAME. It does this by
dynamically resizing the IFRAME to be
the height of the page contained
within it, eliminating any possible
IFRAME scrollbars from appearing while
snugly showing the entire external
content. Think of it as SSI (server
side includes) emulated using DHTML!
This script works in both IE5+ and
NS6+, and for other browsers, supports
the option to either completely hide
the iframe in question or display it
using its default height.
Now, this script differs from the
original in that you can load
additional documents* into the IFRAME
even after the page has loaded, and
the IFRAME will dynamically adjust its
height to fit the new document. So use
this script if you need to not only
display external content via the
IFRAME tag, but intend to change this
content after the page has loaded.

Related

When to call Javascript for ScrollHeight

I have a page with an iframe. The two sites (parent site is php, child site is asp.net 2.0) are on different domains, although I control both of them. Most of the work is done within the iframe. I am using the postMessage function to send information about the total height of the content in the iframe. However, it always comes up as 0, I guess because the script executes before everything is laid out on the screen. Is there a way I can obtain the total height (I think it's scrollHeight, right?) of the child site so that I can send it to the parent?
Thanks!
so you want the parent to adjust the size of iFrame when you got o another page etc.. so suppose your using jquery as the JS lib you can try this trick. in the parent.html do this
$(document).bind('atriggerMessage', function(e) {
//do the iframe size change or other stuff
});
then within the iframe you need to trigger the event. so in the iframe.html
parent.$(parent.document).trigger("atriggerMessage");
I wanted to post my solution in case someone else comes across the same issue.
I ended up putting javascript code in the html markup almost right before the closing tag. This ensured that the page was visible before the body.scrollHeight was called. I don't understand why the body.scrollHeight inside window.onload() or body.onload or $(document).ready() as #shakirthow said above.

Allow click to pass through iFrame to content behind it

The closest thing I can find to what I'm trying to do on SO is this, but sounds like this is not a workable solution anymore and it is not specific to iFrames anyway:
Click through a DIV to underlying elements
Basically I have a DIV that gets added to a page that contains an iFrame. The iFrame contents can be minimized so they don't always take up all the space of the iFrame. The iFrame is transparent so that you can still see the web page behind it. I need to be able to click on the elements in the web page behind it, but have had no luck so far.
They have a roughly 400x400 iFrame but when the contents in it are minimized, you can still click on the web page behind it. I tried doing something similar but can't get it to work.
Even in the transparent regions I cannot click on the page behind it. I also tried using pointer-events:none as mentioned in other posts but this does not help. It only disables the elements in the iFrame but has no affect on being able to click through it.
Do anyone know how to achieve this? A way to have a larger iFrame, where the contents in it can be minimized and you can still click on what's behind the iFrame?
UPDATE:
It would appear that this is not possible when using frames.
Have you tried pointer-events: none?
http://robertnyman.com/2010/03/22/css-pointer-events-to-allow-clicks-on-underlying-elements/
Strategy 1: iFrame Resizer
If you're able to get scripts into both the host page and the page contained within the iFrame, you can use Bradshaw's iFrame Resizer JS.
It will dynamically resize your iFrame to fit its content. Works cross-domain.
The use cases for it include:
You are authoring both the host page, and the iFrame page.
You are authoring either the host page or the iFrame page, and are collaborating with the author of the other page.
I can't tell if your use case meets either of those criteria.
Strategy 2: Overlapping iFrames
Using JQuery, you can toggle the visibility of 2 (or n) iFrames which overlap completely or partially. You can load each iFrame with the same content, or different content. When any iFrame is invisible, you can click through it to the content behind it, whether that's another iFrame, or anything else.
In your application, you would be sizing the 2 iFrames differently: iFrame1="full size", iFrame2="minimized."
In my application (below), the 2 iFrames mostly overlap and have the same content, but I was padding them differently and shifting their position slightly, depending on whether something else on the page was present or absent. I'm also resizing both iFrames dynamically to fit their content using iFrame Resizer (above), but that might not be required for your application.
I recommend using different border colors for your iFrames (below), while you fiddle with their position and size.
I only learned JS like, 5 mins ago, so, my apologies if I've misunderstood your question.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.2/jquery.min.js"></script>
// This is the Bradshaw resizer script. Required iff you need dynamic resizing.
<script src="[https://MyiFramehost.com/web/embed/js/inline.js]"/></script>
<div id="padded" style="width:100%" >
<iframe id="oos_inline" style="border:solid;border-color:green;width:100%;position:relative;padding:65px 0px 0px 0px;top:-65px;"></iframe>
</div>
<div id="normal"style="width:100%;" >
<iframe id="oos_inline_padded" style="border:solid;border-color:blue;width:100%;position:relative;padding:0px 0px 0px 0px;"></iframe>
</div>
<script>
var iframe_padded = document.getElementById("oos_inline_padded");
var iframe = document.getElementById("oos_inline");
if(document.getElementById("home-page")!=null){
iframe.src = "https://the_embedded_site.com";
$(iframe).show();
$(iframe_padded).hide();
} else {
iframe_padded.src = "https://the_embedded_site.com";
$(iframe).hide();
$(iframe_padded).show();
}
// This starts dynamic resizing. Required iff you need dynamic resizing.
iFrameResize({log:true})
</script>
I think you missed:
myDiv.style.opacity = "0";
myDiv.style.filter = "alpha(opacity=0)"; /* For IE8 and earlier */
BTW, use a CSS class instead of applying CSS via JS. Let me know how it goes.

How can I change IFRAME height when the source it's on another domain?

I think this option is not avaiable, but maybe you know some strategies for doing it!
I'm on http://www.mydomain.com, and I put an iframe with jquery of another domain :
​<div id="myContent​​​​​​​"></div>​
$('#myContent').html('<iframe id="myFrame" src="www.anotherdomain.com"></iframe>');​
Well, the page that I load, www.anotherdomain.com, it's mine, so I can add any kind of code!
What I'd like to do is set the height of myFrame regard the real size of the loaded page (which I can't know, it can changes during the time).
Is there a method where I can comunicate to the parent DOM (mydomain.com) the size of the inserted page (anotherdomain.com)?
I don't know it, I dubt so, but why don't ask.
You can send messages (such as the height of the frame) between iframes on different domains using postMessage: https://developer.mozilla.org/en/DOM/window.postMessage
The only solution I found for that was to pass iframe height via url. You can find my test here :
http://jsfiddle.net/Grsmto/nBWrJ/2/ (updated)
This solution works cross browsers (chrome, ff, ie all versions, mobile etc.) and cross domain.
You MUST have access to the iframe code itself AND the iframe host.
You can refresh the iframe height when you want (even if content change) just by calling the publishHeight() function inside your iframe.
This should work without jquery (mostly writen in pure javascript...).
The only inconvenient is that you will have the height in the url like :
http://www.yourdomain.com/index.html#1458px
But you should easily remove it or change it to something less ugly.
EDIT : It seems that Disqus and Twitter use this library to do that : http://easyxdm.net/wp/
EDIT 2 : On your page you put the code on the first jsfiddle page. In your iframe you put the code of the iframe (the red div "myiframe" in bottom right). Hope it's clear...
But check my link below it should be a better and easier solution.
Cross-domain communications are very limited, and impossible depending on the on the remote host. http://www.ibm.com/developerworks/library/wa-aj-jsonp1/ You can use JSONP to try and retrieve information from the remote site, but its very trying and not for beginners.
The work around that I found that worked for me was I used a server side language instead to include the remote file. so instead of < iframe >
I did a PHP server-side include like:
<?php include 'http://www.example.com/file.txt?foo=1&bar=2'; ?>
This of course only applies if you are using PHP. Once I included it that way I was able to manipulate the DOM elements.

Firefox and Safari stylesheet loading time, firing JavaScript event when loaded

We have some JavaScript code that resizes <div/> elements (adjusts height/width/padding/margin etc.) based on the dimensions of a parent <div/> element, specifically the height and width of the parent we use in the calculation. The parent div height and width is defined in a external CSS file, and <link> is used to include the stylesheet, in the <head> section of the page. All stylesheets are included before javascripts. The JavaScript resize code is fired inside of a jQuery document ready event using the standard $(function() {}). All stylesheets and javascripts automatically have timestamps appended to them (Rails application) to ensure they are not cached (in development).
In Firefox 3.6 the resizing works every time. However in Safari 5, occasionally the resizing fails, because the parent height/width is incorrect, which appears to be because the stylesheet has not loaded before the JavaScript. Frustratingly, this happens every few times, and is different depending on the browser/machine load. I can put the resizing code inside a setTimeout() and delay it by 1 second or so and get it to work reliably, but this is not a releasable solution because it is too slow, and still varies by machine. Ideally there would be a way to guarantee the stylesheet is downloaded, then fire the JS resize code.
First of all, is this a bad design, to have JS resizing based on CSS loaded from an external stylesheet? I'm considering trying to place the height and width inline so it is rendered from the server, but this requires significant app code change and tighter coupling to the UI, and I'd like to avoid inline style if possible. Is there a webkit event by chance when stylesheets are loaded? I don't think there is. Any suggestions on a method other than a timeout to ensure all stylesheets are loaded before firing JavaScript? Anyone else experienced differences in stylesheet load order/timing between Webkit and other browsers and have a solution to share? I could use some fresh thinking on this problem.
Note: in general for images, we use the load ($(thing).load(fn(){})) event on images to ensure they are loaded before applying any JavaScript to them. That would be a good pattern to follow if such a thing existed. Thanks!
Co-worker (#johnreilly) found a couple solutions, one polls the document.readyState property when the browser is Safari looking for a value of complete.
Get the real width and height of an image with JavaScript? (in Safari/Chrome)
Another creates a cssLoaded custom event and uses :after pseudo-selector to avoid polling. http://stilbuero.de/demo/cssloaded/
So the first solution is acceptable. I'm putting it in the main javascript file and using $.trigger() to emit a custom event to our handlers that depend on Webkit having fully downloaded the stylesheets.

Growing an Iframe depending on the source inside it (which is another Server)

I use javascript to expand an Iframe to the size of the document it loads to remove any vertical scrollbar, like so:
function resizeIframes() {
$('iframe').load(function()
{
this.style.height = (this.contentWindow.document.body.offsetHeight + 40) + 'px';
}
);
}
Which works well enough for my uses. But now I need to load the Iframe with a website from another server (actually another subdomain, instead of "www.mydomain.com" it's "services.mydomain.com") and according to Firebug I'm not allowed to read properties from other domains via Javascript. I'm guessing some kind of sandbox problem?!
Is there any way to circumvent this or at least get some kind of info about the size of the content? I even would be willing to check if there is a scrollbar and continually grow the iframe until it's gone, but unlike the window object an iframe object does not seem to have a .scrollbars property.
I am sorry if you find this reply to be incomplete (it is). I just don't have code samples with me. I'll sketch the main concept and you will have to fill out the details yourself.
You have to use some tricks to do that since XSS security does not allow frames from one site to access frames from another site:
site1:page1: call iframe (site2:page1) on site two. Let's assume the iframe ID property is "myframe".
site2:page1: run JavaScript (in body.onload) to calculate the size of the current view (I think you should use document.scrollTop etc.). Also run an iframe (site1:page2) passing the needed width in the query string.
site1:page2: read the query string and find out the requested height, update parent.parent.document.getElementById("myframe").style.height
If it's just another subdomain, document.domain should give you the needed access between frames.

Categories

Resources