Behavior, Content, Money – 3 Things you should never give away for free!!!

BCmoney MobileTV

Remotely exchange data between iFrame and parent (jQuery .vs. HTML5)

Posted by bcmoney on November 17, 2010 in AJAX, HTML, JavaScript with No Comments


No Gravatar

One of the many nagging web development problems that the HTML5 working group is addressing with the new HTML specification, is the difficulty in working with content or exchanging data in between an iFrame and the main (origin) page which embeds it, as well as across separate windows (tabs) and domains.

jQuery

Image courtesy of jquery project

jQuery

In order to accomplish the exchange of data between iFrames, while we wait for more browsers to support the new Communications section of the HTML5 spec (more specifically the postMessage function), the following is a quick way to make the communication magic happen with the convenience of jQuery:

 <!DOCTYPE html>
 <html>
 <head>
	<title>Remote iFrame communication - jQuery</title>
   <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.4.js"></script>
 </head>
 <body>
   <iframe id="frameDemo" name="frameDemo" src="test.html" width="80%" height="200"></iframe> 
   
<script type="text/javascript"> function getIframeContents(selector){ $("#frameDemo").load(function(){ response = $("#frameDemo").contents().find(selector).html(); alert(response); $("#responses").html(response).show(); }); } getIframeContents("#test"); </script> </body> </html>


-OR-

Don’t blink, immediately on page load this demo will extract the contents of the “test” <div> from the framed HTML document (using the getIframeContent function), output the value it extracted to the parent HTML document’s DOM (also via an alert, just to make sure you didn’t miss it), then change the value that <div> to something else we specify (using the setIframeContent function).

This can be useful for extracting or passing data from widgets and with other self-contained code that you don’t necessarily want to run within your main page, but from which you might want to snag or update some data. It has possibly lots of other practical uses, for example if you were building a news reader you could use an RSS feed’s link to pull the full content of the link and display it without the user having to leave the page.

NOTE: Though the getting of content should work fine it may require a server-side proxy to grab the content first through a proxied AJAX request, depending on the browser(s) you want to support. Of course, the setting content of the iFrame part will only work if the page is on the same domain as your calling page, due to the same-origin policy restriction, which is unfortunately in place for a good reason.

JS

Image courtesy of wikipedia

JavaScript

What if you don’t have access to jQuery for licensing or dependency limitations at work, or have been hiding under a rock and don’t really know what jQuery is or how to use it? In order to do the same thing in plain-old, vanilla, pure JavaScript without the benefit of full cross-browser support of jQuery, we can still accomplish this by refactoring as in the following:

<!DOCTYPE html>
<html>
<head>
	<title>Remote iFrame communication - JS</title>
</head>
<body>
	<iframe id="remoteFrame" name="remoteFrame" src="test.html" width="80%" height="200">
		Error loading iFrame!
	</iframe>
	<div id="responses">
	...
	</div>	
	<script type="text/javascript">	
	function getIframeContents(id)
	{
		var frame = document.getElementById('remoteFrame');
		var response = childGetElementById(id);
		var incoming = response.innerText||response.textContent; 
		alert(incoming);
		document.getElementById('responses').innerHTML = '<b>remoteFrame said:</b> "'+(incoming)+'"';		
	}
	
	function setIframeContents(id, msg)
	{
		var frame = document.getElementById('remoteFrame');
		var content = frame.contentDocument || frame.contentWindow.document;
		content.getElementById(id).innerHTML = msg;
	}
	
	function childLoaded() {
		getIframeContents('remoteIframeData');		
		setIframeContents('remoteIframeData', '<b>parentFrame said:</b> Goodbye!');
	}
	</script>
</body>
</html>

You then need to add the following additional JavaScript “wake-up call” to the child iFrame:

	parent.childGetElementById = function (id){ return document.getElementById(id); };
	parent.childLoaded();


-OR-

HTML5

Image courtesy of W3C


HTML5

Just for completeness’ sake, here’s how you’ll eventually be able to accomplish the same effect cross-browser, once the HTML5 specification is finalized and fully supported by the modern browsers (not to mention when legacy browsers like IE6/7/8 are long gone, which is hopefully sooner rather than later). The exciting thing is that this should work on mobile device browsers that implement the HTML5 spec as well (can you say goodbye SMS and texting plans?!? I can only wish).

<!DOCTYPE html>
<html lang="en">
<head>
<title>HTML5 postMessage (cross domain)
<style type="text/css">
iframe { width: 100%; border: 2px solid #ccc; }
</style>
</head>
<body>
<iframe id="frameDemoHTML5" src="http://jsbin.com/usidit/7"></iframe>
<script type="text/javascript"> var theFrame = document.getElementById("frameDemoHTML5").contentWindow; var onmessage = function(e) { var data = e.data; var origin = e.origin; document.getElementById('responses').innerHTML = data; alert(data + "(from: " + origin + ")"); theFrame.postMessage("Goodbye... thanks for coming!", "http://jsbin.com"); //set }; if (typeof window.addEventListener != 'undefined') { window.addEventListener('message', onmessage, false); } else if (typeof window.attachEvent != 'undefined') { window.attachEvent('onmessage', onmessage); } theFrame.postMessage("Goodbye... thanks for coming!", "http://jsbin.com"); //set </script> </body> </html>


-OR-

(that download is the same as the one above, I just tossed all the files you’ll need in the same zip…)

Let’s not forget the file from JSBin which has the logic to do the 2-way communication between child iFrame and parent window which embeds the iFrame.

The only weakness of this approach is that you need to have control of the file on the remote domain, or, convince the owners to add in the required messaging code to respond to incoming messages from your domain. Lastly, note how the ability to check the origin functions much the same way as Flash’s crossdomain.xml, which is actually one of the few things I think Flash got right in terms of security and sandboxing requests to whitelisted domains.

 

 

 

 

Leave a Reply

No trackbacks yet.

Posts with similar tags
Posts in similar categories

BC$ = Behavior, Content, Money

The goal of the BC$ project is to raise awareness and make changes with respect to the three pillars of information freedom - Behavior (pursuit of interests and passions), Content (sharing/exchanging ideas in various formats), Money (fairness and accessibility) - bringing to light the fact that:

1. We regularly hand over our browser histories, search histories and daily online activities to companies that want our money, or, to benefit from our use of their services with lucrative ad deals or sales of personal information.

2. We create and/or consume interesting content on their services, but we aren't adequately rewarded for our creative efforts or loyalty.

3. We pay money to be connected online (and possibly also over mobile), yet we lose both time and money by allowing companies to market to us with unsolicited advertisements, irrelevant product offers and unfairly structured service pricing plans.

  • Archives