UFrame: Goodness of UpdatePanel and IFRAME Combined

UFrame makes a DIV behave like an IFRAME that can load any ASP.NET/PHP/HTML page and allows all postback and hyperlink navigation to happen within the DIV - a painless way to make regular pages fully AJAX enabled

Introduction

UFrame combines the goodness of UpdatePanel and IFRAME in a cross browser and cross platform solution. It allows a DIV to behave like an IFRAME loading content from any page either static or dynamic. It can load pages having both inline and external JavaScript and CSS, just like an IFRAME. But unlike IFRAME, it loads the content within the main document and you can put any number of UFrames on your page without slowing down the browser. It supports ASP.NET postback nicely and you can have DataGrid or any other complex ASP.NET control within a UFrame. UFrame works perfectly with ASP.NET MVC making it a replacement for UpdatePanel. Best of all, UFrame is implemented 100% in JavaScript making it a cross platform solution. As a result, you can use UFrame on ASP.NET, PHP, JSP or any other platform.

UFrame does not use IFRAME nor UpdatePanel and thus it is very fast.

<divclass="UFrame"id="UFrame1"src="SomePage.aspx?ID=UFrame1"><p>This should get replaced with content from Somepage.aspx</p></div>

Response from SomePage.aspx is rendered directly inside the UFrame. Here you see two UFrames are used to load the same SomePage.aspx as if they are loaded inside IFRAME. Another UFrame is used to load AnotherPage.aspx that shows photos from Flickr.

What is UFrame?

UFrame can load and host a page (ASP.NET, PHP or regular HTML) inside a DIV. Unlike IFRAME which loads the content inside a browser frame that has no relation with the main document, UFrame loads the content within the same document. Thus all the JavaScripts, CSS on the main document flows through the loaded content. It's just like UpdatePanel with IFRAME's src attribute.

The above UFrames are declared like this:

<divid="UFrame1"src="SomePage.aspx"><p>This should get replaced with content from Somepage.aspx</p></div>

The features of UFrame are:

You can build regular ASP.NET/PHP/JSP/HTML page and make them behave as if they are fully AJAX enabled! Simple regular postback will work as if it's an UpdatePanel, or simple hyperlinks will behave as if content is being loaded using AJAX.

Load any URL inside a DIV. It can be a PHP, ASP.NET, JSP or regular HTML page.

Just like IFRAME, you can set src property of DIVs and they are converted to UFrames when UFrame library loads.

Unlike IFRAME, it loads the content within the main document. So, main document's CSS and JavaScripts are available to the loaded content.

It allows you to build parts of a page as multiple fully independent pages.

Each page is built as standalone page. You can build, test and debug each small page independently and put them together on the main page using UFrames.

It loads and executes both inline and external scripts from loaded page. You can also render different scripts during UFrame postback.

All external scripts are loaded before the body content is set. And all inline scripts are executed when both external scripts and body has been loaded. This way, the inline scripts execute when the body content is already available.

It loads both inline and external CSS.

It handles duplicates nicely. It does not load the same external JavaScript or CSS twice.

Download the Code

You can download the latest version of UFrame along with the VS 2005 and VS 2008 (MVC) example projects from CodePlex:

As you see, the MVC page works fine and it can read data from Request and post data to the same MVC URL. You can use regular MVC libraries including the new helper libraries released with Preview 2.

Error Handling

Just like IFRAME, UFrame can show error pages properly. Following shows when an unhandled exception occurs, UFrame is perfectly capable of parsing the error response and show it inside the container DIV:

Internals of UFrame

UFrame makes XMLHTTP calls to the URL specified in src attribute. It expects HTML output from the source. It then parses the HTML and finds out all inline and external script and stylesheets. Then it injects the stylesheets and scripts into the browser DOM. It then waits until all external scripts are downloaded. When done, it injects the loaded body HTML inside the DIV and executes all inline scripts. This way, all inline scripts can access the DOM elements properly. When the HTML is completely loaded and all scripts are executed, it hooks all <form> and <a> tags to make sure the forms do not submit themselves and the hyperlinks do not navigate the browser away. Instead, they are handled to make sure the postback and navigation happens via the UFrame.

First step is to find out all the DIVs that want to be UFrames. For each DIV, one instance of UFrame class is created.

Here you see UFrame offers a lot of HTML templating feature. It allows you to show custom progress message when UFrame is loading or posting information. You can specify custom HTML that is injected before and after each response HTML specified in beforeBodyTemplate and afterBodyTemplate. It also offers callback before and after content is loaded or posted so that you can control what UFrame sends to server and what it receives from server.

The UFrameManager contains all the behaviors of UFrame. When init is called, it creates one instance of UFrame class and associates that to the DIV.

The real challenge is properly parsing the HTML and then loading and executing the JavaScripts and stylesheets received from the response. There are lots of hacks and tricks involved in making this work successfully across all browsers. Fortunately, most of it is already handled by jQuery especially the complex steps in loading external script and waiting for it until it downloads properly and then executing the script in a cross browser way.

The processHtml function first parses the returned response and constructs an object model that has the body content, inline and external JavaScripts and Stylesheets. It then adds all the <link> tags to the browser DOM. Some trick is involved here to make it work across browsers. Then it injects all the inline stylesheets to the browser DOM. After that, it loads all the external JavaScripts. When they are loaded and executed successfully, it injects the body HTML from the response (stripping off all script, link and style tags). Then it executes all the inline scripts. Once done, it hooks on all form and hyperlinks to intercept any form post or navigation.

UFrameManager's parseHtml function parses the given HTML and builds an object model that contains the body HTML without script and style tags, collections of internal and external script and stylesheet tags. The result object looks like this:

Here you see the cross browser way of injecting CSS to the browser DOM. Internet Explorer has a special way of taking CSS text. First you need to create a style tag and then use IE's proprietary "stylesheet" property to set the CSS text. All other browsers just take CSS as a text node.

Next black art is adding <link> tags to the browser DOM. Just creating a <link> tag and injecting it into the <head> does not work. For IE6, you have to switch to the browser's window object's context and then inject it to the <head> tag.

The counter scriptsToLoad is 0 when all external scripts get loaded either successfully or some fail to load. So, when scriptToLoad is 0, we can proceed with adding the body HTML inside the container DIV and executing the inline scripts. The cross browser dark magic of loading external scripts property is handled by jQuery. Just for your information, adding a <script> tag to the <head> tag is not all you need to do. For some browsers like Safari, you have to make XMLHTTP call to load external JavaScript and then call eval to execute the JavaScript on window object's scope.

The final piece of dark magic is in injecting the body HTML, executing inline scripts and then hooking all forms and hyperlinks. Here's how they are done:

Here you see, the inline script execution and hooking forms and hyperlink are deferred using a timer because not all browsers immediately make the DOM available to Javascript when a large amount of HTML is injected into the DOM using innerHTML. So, the timer gives browser some room to build the DOM from the html fragment.

UFrameManager's hook function has the real secret of IFRAME like behavior. It hooks on all <form> tags and prevents them from submitting. Instead it captures the data being submitted and makes an HTTP POST to the action URL. When it receives the response, UFrameManager.loadHtml is called and the new response is injected inside the container DIV. The hook function also intercepts clicks on hyperlinks and instead of redirecting the browser to the URL, it makes an HTTP GET call to the link passing arguments from the original hyperlink's href and renders the response inside the container DIV.

Basically the idea is to find the doPostback function's parameters and pass them directly to the __EVENTTARGET and __EVENTARGUMENT hidden fields in the containing form. Then the form is submitted in AJAX way and the response is loaded inside the container DIV as usual. The code for this kind of postback is taken from the code from ASP.NET generated __doPostback function, which is like this:

Find all form elements that send data when a form is submitted. For instance, checkbox, radio button, select box, hidden input fields and so on. However, only those elements are selected which are enabled and for some elements like checkbox and radio button, only when they are selected.

Find the UFrame instance that is attached to the form and use the configurations from that UFrame instance

Prepare the HTTP POST payload that will be submitted to the form's action URL

Make an HTTP POST to the form's action URL

Process the response and show inside the container DIV

Serving Pages as widgets using UFrame

UFrame renders a page inside a DIV. As a result, it's a great way to widgetize your pages. You can build small independent pages that can be loaded via UFrame to behave like widgets. In the example, I have shown such a widget which shows photos from Flickr.

However, when you load same page more than once within the same document using UFrame, you will run into HTML element ID conflicts. ASP.NET page serves HTML elements with fixed ID. So, loading two instances of the same page will result in duplicate element IDs on the main page. For example, if a page emits a button with ID "ClickMe", if you load two instances of that page using two UFrames, there will be two buttons with ID "ClickMe". This will prevent proper postback and event firing.

In order to solve this, each instance of the page needs to produce controls with some unique ID. SomePage.aspx solves this problem by taking an ID in the query string and using that ID to prefix all ASP.NET Control's ID. For example, the first instance of SomePage.aspx is added using UFrame1 ID:

<divclass="UFrame"id="UFrame1"src="SomePage.aspx?ID=UFrame1"><p>This should get replaced with content from Somepage.aspx</p></div>

The second instance is added using a different ID:

<divclass="UFrame"id="UFrame2"src="SomePage.aspx?ID=UFrame2"><p>This should get replaced with content from Somepage.aspx</p></div>

The SomePage.aspx uses the ID passed in the query string to prefix all ASP.NET Control's ID. This way, all ASP.NET controls emitted by SomePage.aspx gets a unique ID and prevents the duplicate ID problem.

Using this approach, you can host many instances of same page on the main page and thus make those small pages behave like widgets.

References

The UFrame has been inspired by jQuery, HtmlParser and jFrame. UFrame uses jQuery and a modified version of HtmlParser. The idea of submitting a form in Ajax way has been taken from jFrame.

Conclusion

UFrame fills in the shortcoming of AJAX and UpdatePanel in ASP.NET MVC. It's a cross browser, cross platform solution to make regular pages behave like fully AJAX enabled pages. It takes away the challenges of building complex AJAX enabled pages by giving you the flexibility of using standard form post based web programming.

We use IFrame because we want to load old versions of our pages inside more recent pages. Therefore the JavaScript loaded in the UFrame needs to be isolated from the one of the hosting page. Is this possible with UFrame?

I have a small Mvc application that has one view page and 3 webforms, i have used the ViewPage to load the 3 webforms at the same time. Is there a way that i can cause the first form to reload if i make changes on the second one?

Since i want to pass data from the second form to the the first form using sessions

Hi Omar, I am trying to utilize your UFRAME with my portal application. Within portal, I am using query 1.7.1. But UFRAME works fine with jquery-1.2.3.js only.
I have tried lower versions with no luck.

Hi,
I loved the UFrame Idea and method, it is fast as i needed. But i have a problem, I have to update Second/Third Uframe on the Control click(Checkbox, button, linkbutton etc.) placed in the First Uframe.
This is some kind of Urgent because i am stuck here and my boss have an eye on me .
Is it Possible???
Please help me...

You can deliver a script from the first UFramed page to find the second/third Uframe and do a refresh. All UFramed pages are made part of the main page. So, you can call javascripts from the main page or any uframed page as if they are on the same page.

actually, i'm using updatepanel at my asp.net page because i need the partial refreshing at my page.my page including 3 parts. at the first it just shows the top menu, once user clicks on any of the top menu it will shows the left sub menu and by clicking on any of the sub menu it will shows the content of the sub menu, which is including table with add, edit, delete and insert button. for the table i have used the listview.

Now i want to show one external page at the 3rd panel, which means when the user click on the sub menu the 3rd panel load the another page. for example my page name is default.aspx and once the user click on the sub menu at the default.aspx page it shows the Product.aspx page at the 3rd panel. i don't want to use the iframe and i have gone through uframe at the http://uframe.codeplex.com/ and this article but i couldn't use the uframe at my page.Could you please guide me how to use uframe at my page or any other way to load the other page at the 3rd panel of my default.aspx.appreciate your consideration.

I have spent many hours looking to do exactly what you have accomplished here. Also, excellent accomplishment, I have determined that there are a few corrections necessary for my app to work properly, specifically, I have a list box with multiple item selections and when the user clicks on one of many items to be selected, the UFrame fires a postback, which is an unintended/unwanted functionality.

However, the major drawback I found, which makes my app unusable is the inablity to retain data stored within the ViewState accross postbacks. Therefore, I have made following addition to UFrame.js and it seems to be working as desired; seems too easy somehow. Let me know if agree on these changes or if you have any concerns against this kind of additions/usage.

Ok, so I have a few questions about it.
1) Is there a way (function) built into UFrame that I could use to determine if someone hits a page that is built to show up inside the UFrame? I have several "child" pages that I would like to have redirect the user to the parent page if the parent cannot be detected.

2) Maybe a bug: On one of my child pages, I have added a GridView with a CommandField option to enable deleting items. When the GridView posts back, it reloads breaking out of UFrame and its parent page. Is there a way to code around this with either VB or Javascript?

If I can get these answered, I will be good to go. Either thanks UFrame!

At the moment in the .aspx page my UFrame is pointing to there is an asp:DropDownList bound to a SqlDataSource. When I run the page to test things I get an error every time the selection in the list is changed.

The src of my UFrame is a html document containing a form which I need to post to a dynamic URL. So first I need to set the Action of this form, populate the input element with some data and then post the form.

How can I access the form and input elements inside the UFrame from the parent page.
Thanks

First of all, I'd like to thank you for such an amazing work. If not for this current problem I am facing, the implementation I am attempting would've went flawless.

Now, the problem at hand: Inside a VS2005 project, I am loading an .aspx page inside an UFrame which gets a listbox/select (Tried both) populated via a PostBack from another control inside this same page.

The PostBack and the data binding runs fine, and the page itself works properly alone, but no matter what I do when loaded inside the Uframe, it will immediately post back whenever I click on an item from said listbox/select. This is rather problematic, because multiple selections are needed.

As I said, I've tried both controls, tried AutoPostBack=false, and some other tricks like attempting to catch the click client-side via JS, with no luck.

I am quite sure I am doing something wrong, but after reading the posts here and in codeplex, I just can't figure it out what's wrong. Any help will be greatly appreciated.

Help, I'm doing something wrong. I was trying to include an external site in a UFrame, but must be doing something wrong. I have downloaded the .js file to my site and added the reference to them in my page header. I thought then all I needed to do is add the

tag which I did: <div class="UFrame" id="UFrame1" src="http://totherescuedfw.com/index.html?ID=UFrame1">
<p>This should be replaced by the contents of the above URL</p>

Did I do this right or am I missing something? With Safari I get no error nor the src site, just the default sentence between the

I'm looking for the best form of build a web application with an Outlook style menu.
The menu must be configurated at the first load of the application, after validate the user, so only the options available for that user are visible.

Then when the user select an item in the menu this action loads the correspondent page in another frame of the page without refreshing the rest of the contente, including the menu.

Any idea why the option button list causes an error on the server when it is nested within a wizard control? Cool concept though. Personally I could care less if it standards compliant so long as it works in all major browsers. I think the resolveUrl function needs to written better, Firefox still can show issues with it. If you can get this thing working reliably with multiple nested asp.net controls I would definitely use it.

Just curious if anyone is using this now in as limited a dev frame as PhP, and is having no problems on Safari, Chrome, FF, Opera ?

thanks, Bill

"Many : not conversant with mathematical studies, imagine that because it [the Analytical Engine] is to give results in numerical notation, its processes must consequently be arithmetical, numerical, rather than algebraical and analytical. This is an error. The engine can arrange and combine numerical quantities as if they were letters or any other general symbols; and it fact it might bring out its results in algebraical notation, were provisions made accordingly." Ada, Countess Lovelace, 1844

I'm developing a policy acceptance application where I work and our policies are stored as BLOB Data in an Oracle Database. Each blob contains the HTML markup needed to display the policy.

I'd like to use UFrame to display these policies as some of them have checkboxes and radios that you need to capture the value of, but its not clear if UFrame will support having BLOB data read into the div and if there is some way to dynamically set the src attribute so that it would work with these documents coming from a database.

Can uFrame be used with BLOB Data and if so, how should I go about setting it up to work in this way. Any help is greatly appreciated.

I want to display Charts inside the uframe on the container page i.e. on the somepage.aspx .The fusion charts/graphs renders with script tag and inside it there are some function which replaces the div.
Its working with mozilla but in ms internet explorer
it gives the javascript error..as
"theForm.Element.length is null or not an object"

The script is as:
I want to run this script inside the container page (somepage.aspx)

To fix make a little change inside of UFrame.js.
Find initContainers() method and just change "div[@src]" to "div[src]".
Very strange. "div[@src]" is valid xPath expression. But "div[src]" is valid w3c css selector.
1.3.1 doesn't woth with xPath now ?

Did you ever figure this out? I am trying to get it to work inside a modal popup and when it does a postback it just opens the child page in the browser. Oh and I just realized this post is almost a year old...

Hello,
I have one main page i.e. Default.aspx in which I have <div class="UFrame" id="UFrame1" src="Pages/RadDocPage.aspx"> and in RadDocPage.aspx I have telerik:RadScriptManager & telerik:RadDockLayout, telerik:RadDockZone etc.
When i load the main page i get this error BUT the when i run the RadDocPage.aspx page individully then its work fine so there is no error in references, web.config settings etc. Now i am in real confusion whether to go ahead with this approach or not, It would be great help of yours if you could suggest me some thing.
Thanks in Advance.

I use this in a form and load form in uframe when i change selected item in DropDownList i see this error "Microsoft JScript runtime error: 'theForm.__EVENTTARGET' is null or not an object".
pls help me to solve this.
tnx.

UFrame is kind of replacement of UpdatePanel functionality for ASP.Net MVC, and it is the only main usage of UFrame ?
Is there any practical use of UFrame let's say in dropthings portal?
I noticed download at codeplex for VS2005 which was probably aimed to show UFrame with classical WebForms ASP.Net but it is without sln file and "limitations.txt" does contain a big list. Do limitations apply to any ASP.Net WebForms including latest 3.5 or they are ASP.Net 2 limitations.

This is probably pointed out somewhere but I never found it. After playing with files long enough I finally realized you have to put the pages you plan on calling in a subdirectory. I don't know if that's 100% accurate but I couldn't get the files to load otherwise, I would continually get an error saying this object doesn't have this property or method. Once I changed the path to a subdirectory calling the exact same file everything worked great.

*this only seems to be the case for internet explorer

It might be a good idea to inform people of that in the usage information section of your articles.

Hi Omar,
I have a few questions:
1. "UFrame does not use IFRAME nor UpdatePanel and thus it is very fast."
Have you run comparison tests? Could running jscripts and HTTP POST take time comparable to native IFrame load?Is it quicker for all major browsers?

2. Limitaton of UFrame to not support cross-domain URLs should be explained in the article, when you compare it with IFrame, as well as reference to your article how to workaround it by creating proxy.

And unrelated to IFrame question
3.Did you consider functionality to ensure unique IDs to implement in JavaScript(e.g. if some optional attribute will be specified) rather than on server code for each page?