6

I am loading an iframe inside a page, which the length of the content of the iframe will be changed from time to time. I have implemented the following solution. However the height is fixed as the dyniframesize only get call when iframe.onload.

It is possible to have the iframe to be resized accordingly from time to time the height of the iframe changed?

<iframe src ="popup.html" frameborder="0" marginheight="0" marginwidth="0" frameborder="0" scrolling="auto" id="ifm" name="ifm" onload="javascript:dyniframesize('ifm');" width="100%"></iframe> 

function dyniframesize(down) { 
var pTar = null; 
if (document.getElementById){ 
pTar = document.getElementById(down); 
} 
else{ 
eval('pTar = ' + down + ';'); 
} 
if (pTar && !window.opera){ 
//begin resizing iframe 
pTar.style.display="block" 
if (pTar.contentDocument && pTar.contentDocument.body.offsetHeight){ 
//ns6 syntax 
pTar.height = pTar.contentDocument.body.offsetHeight +20; 
pTar.width = pTar.contentDocument.body.scrollWidth+20; 
} 
else if (pTar.Document && pTar.Document.body.scrollHeight){ 
//ie5+ syntax 
pTar.height = pTar.Document.body.scrollHeight; 
pTar.width = pTar.Document.body.scrollWidth; 
} 
} 
} 
</script> 
m59
  • 43,214
  • 14
  • 119
  • 136
user2625363
  • 845
  • 2
  • 10
  • 15

5 Answers5

9

To my knowledge, there isn't a very natural way of doing this, but there are some options.

setInterval()

You could use setInterval() to repeatadly check the iframe's content height and adjust it if needed. This is simple, but inefficient.

Event Listeners

Any change of content in the iframe's content (and therefore height) is usually triggered by some event. Even if you're adding content from outside of the iframe, that "add" is probably triggered by a button click, for example. Here's something that might work for you: Live demo here (click).

var myIframe = document.getElementById('myIframe');

window.addEventListener('click', resizeIframe);
window.addEventListener('scroll', resizeIframe);
window.addEventListener('resize', resizeIframe);

myIframe.contentWindow.addEventListener('click', resizeIframe);

function resizeIframe() {
  console.log('resize!');
}

Mutation Observer

This solution works in all up-to-date browsers - http://caniuse.com/mutationobserver

Live demo here (click).

It's really simple and should catch the relevant changes. If not, you could combine it with the event listener solution above to be sure things are updated!

var $myIframe = $('#myIframe');
var myIframe = $myIframe[0];

var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

myIframe.addEventListener('load', function() {
  setIframeHeight();

  var target = myIframe.contentDocument.body;

  var observer = new MutationObserver(function(mutations) {
    setIframeHeight();
  });

  var config = {
    attributes: true,
    childList: true,
    characterData: true,
    subtree: true
  };
  observer.observe(target, config);
});

myIframe.src = 'iframe.html';

function setIframeHeight() {
  $myIframe.height('auto');
  var newHeight = $('html', myIframe.contentDocument).height();
  $myIframe.height(newHeight);
}

Honorable mention to: overflow/underflow events.

Read about it here (there's A LOT to it).

and see my demo here (doesn't work in IE 11!).

This was a cool solution, but it's no longer working in IE. It might be possible to tweak it, but I'd rather use one of the above solutions, even if I had to fallback to a 1 second setInterval for older browsers, just because it's a lot simpler than this solution.

m59
  • 43,214
  • 14
  • 119
  • 136
  • When using MutationObserver, in webkit it will fire before images have finished loading, so you have to detect added/changed IMG nodes and then attach load listeners to them. – David Bradshaw Jun 05 '14 at 16:33
  • @DavidBradshaw The last option seems viable once again. – m59 Jun 05 '14 at 16:40
6

I wrote a small Library that uses mutationaObserver and eventListners, with fall backs to setInterval for IE8-10 and works for both same domain and cross domain. It can size both height and width.

http://davidjbradshaw.github.io/iframe-resizer/

David Bradshaw
  • 11,859
  • 3
  • 41
  • 70
  • 1
    Only that worked for me, due to the complexity of the page. Thank you for sharing with the Community have. Great example. =) +1 – Florida Feb 11 '15 at 23:08
4

iFrame View

<script type="text/javascript">
    var height = $("body").outerHeight();
    parent.SetIFrameHeight(height);
</script>

Main View

<script type="text/javascript">
    SetIFrameHeight = function(height) {
        $("#iFrameWrapper").height(height);
    }
</script>
Owen
  • 4,229
  • 5
  • 42
  • 50
2

You can use custom events to signal between the iframe and the parent.

In the iframe:

if (window.parent !== window) {
  window.oldIframeHeight = 0;
  window.setInterval(function() {
      var currentHeight = document.body.offsetHeight;
      if (currentHeight !== window.oldIframeHeight) {
          window.parent.postMessage(currentHeight.toString(), "*");
          window.oldIframeHeight = currentHeight;
      }
  }, 100)
}

Then, in the parent:

window.addEventListener("message", function (e) {
    var h = parseInt(e.data, 10);
    if (!isNaN(h)) {
        $('#iframe').height(h)
    }
}, false);
Owen
  • 4,229
  • 5
  • 42
  • 50
Stephen Thomas
  • 13,843
  • 2
  • 32
  • 53
0

Actually you should do it from iframe by accessing parent window and changing iframe's height.

Because document in iframe usually knows better if the it's body changed it's size (you can actually bind it to something like body.onload instead of using intervals to check if something has changed in iframe).

haldagan
  • 911
  • 5
  • 16
  • Could you expand on how the body "knows" when it changed its size? – m59 Dec 26 '13 at 18:42
  • If your iframe is capable of dynamically changing it's height (like inserting some data from ajax requests) you can always "inject" the code like window.parent.document.getElementById('myframe').style.height = window.document.body.offsetHeight (or smth like that) right after inserting data from ajax. Otherwise you will need this code only in body.onload in your iframe. – haldagan Dec 26 '13 at 18:46
  • Your answer is not suggesting "dynamic" resizing. Having to manually call the update function after making an ajax call is obvious. He wants it to update itself. – m59 Dec 26 '13 at 18:50
  • Well, (IMO) your solution seems a bit "dirty" to me as well as obvious too. I just suggested the "right way to do it" (as i see it). – haldagan Dec 26 '13 at 18:56
  • The first solution, I noted is inefficient and I included for completeness. The second solution is clean and simple. The third is awesome and super efficient, but complicated. I'll add it in a moment. I'm not going to downvote this one personally, I was just pointing out that your answer isn't related to the question..I thought you might appreciate knowing that. – m59 Dec 26 '13 at 19:00
  • I reread the question twice and still don't see how my solution can be irrelevant to the question. I'll wait for your third solution. – haldagan Dec 26 '13 at 19:08
  • Title: **auto resize iframe height when the height of the iframe content change** I'm not going to argue it anymore. – m59 Dec 26 '13 at 19:12
  • "**when** the height of the iframe content **change**" (checking each iframe event is ENOUGH but not NECESSARY, when changing height from iframe itself on content height change is NECESSARY AND ENOUGH) I'm quitting this conversation too. – haldagan Dec 26 '13 at 19:17