For example the Yahoo mail in the late 90's was using framesets for their user interface. After that in the early 2000 till 2006 they changed to the one page per view approach. Now till the days of this article we can see that they are AJAXifying their mail portal and they are back again to the multi-frame approach.
What I want to tell here that multi-frame design is so good to be let behind and there are many ways to overcome the difficulties. And here we are going to put a simple framework for safe communication in a multi-frame environment.
To demonstrate the idea, I will give an example of a frameset that has three frames: top, left, and right. See the picture below:
Following is the HTML source for the frameset page:
<frameset rows="100,*" >
<frame name="top" src="top.htm" />
<frameset cols="300,*" >
<frame name="left" src="left.htm" />
<frame name="right" src="right.htm" />
The top frame will have three buttons named: Red, Yellow, and Green. Clicking any of these buttons should change the background color of the right frame to the same color mentioned on that button.
The right frame has a text box and a button. Clicking that button will set the text in the blue area within the left frame to the same text entered in the text box.
As you can see what we have is a frameset with three simple child frames. Following the HTML source for each frame:
<input type="button" value="Red" />
<input type="button" value="Yellow" />
<input type="button" value="Green" />
<div>Text from the right frame will go here:</div><br />
<textarea id="txtArea" style="background-color:#E0E0FF" readonly></textarea>
<input id="txtInputBox" type="text" size="60" /><br /><br />
<input type="button" value="Set The Text On The Left Frame" />
function setRFBGClr(clr)//Set right frame background color
As you can see, this function will access the "right" frame directly from the parent page (the frameset) and set the body background color. Now on each button within the top page I have implemented the "onclick" event by adding the following script respectively:
...value="Red" onclick="setRFBGClr('#FF0000')" />
...value="Yellow" onclick="setRFBGClr('#FFFF00')" />
...value="Green" onclick="setRFBGClr('#00FF00')" />
function setLFText(txt) //Set left frame text
<input type="button" value="Set The Text On The Left Frame" onclick="setLFText(txtInputBox.value)" />
Until now, running the sample will get everything to work fine or at least as it appears so. Where is the problem then? Suppose that you have a slow Internet connection and that the left frame is heavy loaded with HTML contents, which will take some time till the page is loaded completely. During this time, as we assumed, the left frame will not be ready to accept direct communication from other frames, and that will yield some scripting errors every time you try to set the left frame text from the right frame.
If you think this is not a real problem and most probably you won't encounter it during the normal navigation on your Website; imagine that you are implementing a mailing system, something heavy like Gmail or the new Yahoo mail AJAXfied interface. A lot of operations are involved and many processes run in the background while you are navigating, typing, or just reading your mail. This huge and complicated infrastructure requires a decent synchronization between different frames and different pieces of scripts. In similar situations the direct access to frames within the same frameset is no more a robust way.
What we are going to do about that is to implement a safe frameset communication framework, sounds complicated but it is really simple, let's see how:
The parent page (the frameset page) will be the maestro page; it will receive and dispatch jobs from and to all child frames. This comes from the fact that it is the first page loaded before all the child pages and it always will be ready to be accessed.
First I will start by adding the following script to the parent page "frameset.htm" (note that for this script to work fine, it should be placed within the "head" tag):
var MSG_SET_BG_COLOR = 1
var MSG_SET_TA_TEXT = 2
//Message Queue object
var MessageQueue = new CMessageQueue();
var Q = new Array();
We will use "MessageQueue" to post commands from the child frames to the parent frame which on its turn will work as a source of commands to other child frames. Notice also the message id's which will be used to identify messages on the child pages.
The following script will be added to all the child frames ("left.htm", "right.htm", and "top.htm"):
var arrRet=new Array();
while(msg = window.parent.MessageQueue.nextMessage())
"HandleMessageQueue()" function iterates on all the messages within the message queue and handles only those targeted to this frame. As you can see under the "default" keyword within the "switch" statement, all the messages that are not targeted to this frame will be pushed back to the message queue to be handled somewhere else.
You may see also that "HandleMessageQueue()" function is set to be called periodically within intervals of 600 milliseconds. You may change this interval to best fit your case.
In the following last steps I will do some modifications on each page so it can accept the new commands and behave exactly the same way as was with the direct frame communication.
For the left frame we will add the following script to the switch statement:
For the right frame we will add the following script to the switch statement:
For the right frame also we will modify the function "setLFText(txt)" as following:
function setLFText(txt)//Set left frame text
For the top frame we will modify the function "setRFBGClr(clr)" as following:
function setRFBGClr(clr)//Set right frame background color
Now if you run the frameset page in the browser you will notice that everything is working exactly as with the old direct method but with a slight neglectable delay after any request to a certain command (you may control this delay by reducing the interval milliseconds for calling the "HandleMessageQueue()" function).
Downlod the complete source code:
Using message queue for synchronizing communication between different frames will always be safer and you don't have to worry which frame is loaded first. And if a certain frame is not ready for receiving requests, the message will keep cycling until this frame is ready.