Link to home
Start Free TrialLog in
Avatar of Sivakatirswami
Sivakatirswami

asked on

Can a parent page div dynamically respond to changes in the height of an iFrame it contains?

1) go to this page:  http://www.himalayanacademy.com/view/lexicon
2) click the letter "e" to get all words beginning with the letter "e"
3) scroll way down the page until the header and everything is scrolled out of view.
4) now click on one of the "See:" entries at the end of a word

Voila! You will see your screen goes blank... now scroll up to see the definitions related to the "See also" entry.

So problem/challenge: This is an enyo javascript app that we are putting into an iFrame. The enyo app dynamically renders results fetched with an Ajax call to the MySQL database with the words, definitions and their related  "See:" entries.

The only way I could make sure the parent page would hold all the definitions was do so a silly hack and set the dev that hold the iframe to class "app" and set the height to 20,000 px.

So, yes, it holds all the definitions (well not even 20,000 holds  all definitions for "s", but it works) but when we do a new Ajax call to fetch for example see entries for some word that only has 2-3 matches, these are rendered back into the same div/iframe, but the parent page has no idea about the content change. I tried to set .app{height:auto;} but that did not work. It opens fine with the list of letters to click on, but when you click on a letter and the JS calls data from the server and fills in the div, containing div that holds the iFrame does not grow to match the required entries.

Any ideas for a solution to this?

Of course the best answer is: don't use iFrames for this kind of content. In the long run I think I need to get our page assembly system (RevIgniter) to drive the enyo app (renderInto(#SOME DIV# should work)  directly into it's own page and not use and iFrame, but until then, I'm hoping for a solution to the issue:

Getting in iFrame's parent page to dynamically respond to changes in the height of the iFrame content.
Avatar of Element1910
Element1910
Flag of United States of America image

Try this:
$(window).resize(function(){
    $("#id_of_content_div").height($(window).height()-$(".app").height());
});

Open in new window

Avatar of Sivakatirswami
Sivakatirswami

ASKER

OK looks promising but I'm not getting anywhere.

Testing now on the staging server... I removed the .app height: 20000px;  declaration for now. So we are stuck here:

http://dev.himalayanacademy.com/view/lexicon/

which dynamically assembles the page by calling the iFrame into the main site wide wrapper. In the DOM, the iFrame is inserted into the first div class="article-wrapper" (view the generated source), which I'm assuming should be the responsive DOM element since it is the immediate parent of the iFrame (Perhaps that is not what we should be targeting... )

So I was thinking I would need to implement your solution as:

$(window).resize(function(){
    $(".article-wrapper").height($(window).height()-$(".app").height());
});

Open in new window


in the iFrame itself, because the event listeners are all in the iFrame, so I'm again assuming when we click, e.g. "e" and the app fetches data requiring, say 1800px in vertical space to show... that would be the window resize trigger as well, which then tells the div "article-wrapper" to change height. But it's not happening.

http://dev.himalayanacademy.com/media/apps/web/lexicon

<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
		<title>Hindu Lexicon</title>
		<link rel="shortcut icon" href="assets/favicon.ico"/>
		<!-- -->
		<meta http-equiv="Content-Type" content="text/html; charset=utf8"/>
		<meta name="apple-mobile-web-app-capable" content="yes"/>
		<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
		<!-- css -->
		<link href="/media/apps/web/lexicon/build/enyo.css" rel="stylesheet"/>
		<link href="/media/apps/web/lexicon/build/app.css" rel="stylesheet"/>
		<!-- js -->
		<script src="/media/apps/web/lexicon/build/enyo.js"></script>
		<script src="/media/apps/web/lexicon/build/app.js"></script>
		<script>
		$(window).resize(function(){
                    $(".article-wrapper").height($(window).height()-$(".app").height());
                          });
          </script>		

	</head>
	<body class="enyo-unselectable">
		<script>
					
			if (!window.App) {
				alert('No application build found, redirecting to debug.html.');
				location = 'debug.html';
			}
			new App().renderInto(document.body);

		</script>
	</body>
</html>

Open in new window


I also tried insert your resize function into the main wrapper just above the iFrame call

like this

<script>
$(window).resize(function(){
    $(".article-wrapper").height($(window).height()-$(".app").height());
});
</script>

<style type="text/css">
	.app {
		width: 100%;
		height: auto;
	}
</style>

<iframe class="app" src="/media/apps/web/[[ gData["record"]["file_id"] ]]"></iframe>

Open in new window


That also does nothing.

Assuming your idea is the solution and I'm just implementing it wrongly, then, I'm missing something. If need be, our page assembly system can dynamically insert that JS into the head element if that helps (should not matter, right?)
ASKER CERTIFIED SOLUTION
Avatar of Element1910
Element1910
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Well the solution at SO is only partial: i) resizes on initial opening ii) offers a user toggle. But I'm not seeing the option for the parent page to dynamically resize it's height when the iFrame grows vertically. Your solution looks like it could work if I knew how to implement.  Let me ask more descrete questions:

1) Did you put your window re-size function in the iFrame or the parent page that holds it?
2) do these functions work with classes or just ID?

Meanwhile... still digging...
We found a solution which used some input from SO as suggest by Element1910. Actually we only got a bit of info from Stack Overflow and my brainy developer in Brazil made it work. We will award points to Element, at least for the sake of participation.   For documentation porpoises (we live in Hawaii) in case it is helpful future users needing a solution to this challenge :

1) It's important to realize that for security reasons, the parent page of an iFrame cannot execute Javascript on page of the iFrame. OTOH: the iFrame *is* allowed to call functions declared in the parent page.

2) The parent page/ page containing the has this JS:  (we had to do a lot of writing to the log to determine the event timing:)
<script type="text/javascript">
function alertsize(pixels){
	console.log("somebody called alertsize to change the size to "+pixels);
	$('#webapp').height(pixels+50);
}]

Open in new window

# where the iFrame is dynamically instantiated by our RevIgniter page assembly system.

<iframe id="webapp" src="/media/apps/web/[[ gData["record"]["file_id"] ]]"></iframe>

# the generated path is:

<iframe id="webapp" src="/media/apps/web/lexicon/"></iframe>

3) the inferred call in the URL is (obviously) "/media/apps/web/lexicon/ index.html"  which is the actual Enyo app container with this...
#head of doc: 
		<link href="/media/apps/web/lexicon/build/enyo.css" rel="stylesheet"/>
		<link href="/media/apps/web/lexicon/build/app.css" rel="stylesheet"/>
		<!-- js -->
		<script src="/media/apps/web/lexicon/build/enyo.js"></script>
		<script src="/media/apps/web/lexicon/build/app.js"></script>
	</head>
<body class="enyo-unselectable">
		<script>					
			if (!window.App) {
				alert('No application build found, redirecting to debug.html.');
				location = 'debug.html';
			}
			new App().renderInto(document.body);

		</script>
	</body>

Open in new window

4) Now the tricky bit is to get the enyo app to trigger the "alertsize" function *after* it fetches new content from the AJAX call for data from the data base... so Andre added this function in the app.js where the enyo "this.render" triggers the "rendered" function, which in turn triggers the parent page to resize:
rendered: function() {
	    this.inherited(arguments);
	    this.log("Rendered!");
		var el = this.$.wordList.hasNode();
		var newsize = el.scrollHeight + 500;
		this.log("trying to change the size of the iframe to "+newsize);
	    parent.alertsize(newsize);
		this.log("after the alertsize call");
	},
	  processSearchResults: function(inRequest, inResponse) {
	    if (!inResponse) return;
	    this.$.wordList.destroyClientControls();
		if (!inResponse.error) {
			this.log("found " + inResponse.entries.length+" words");
		    enyo.forEach(inResponse.entries, this.addDefinition, this);
		} else {
			this.$.wordList.setContent(inResponse.error);
		}
	    this.render();		
	  }

Open in new window

It Works!
Sivakatirswami - I stay from Hawaii too, brah! :) Glad I could help out a fellow islander.
Aloha... if you are ever on Kauai, come visit!
will do...get friends from there. I stay from Waialua, Oahu (currently live Makakilo though).