Thursday, September 2, 2010

jQuery UI Frame Dialog - Loading Pane

An updated posted is located here.  This includes modifications to the plugin to avoid multiple iFrame source loads.

I like to use dialogs.  Specifically, I like to use inline dialogs rendered within the current window.  A popular implementation is the jQuery UI Dialog Widget.  I also like to render full page content in dialogs via iFrame object; however, jQuery UI Dialog Widget does not provide this functionality out-of-the-box.

There is a plethora of home grown solutions for rendering iFrames wrapped within the jQuery UI Dialog Widget; however, none really fit well with what I wanted to do.  That is, until I found the jQuery UI Frame Dialog Plugin.  The jQuery UI Frame Dialog Plugin provides extensions to the jQuery UI Dialog Widget for rendering iFrame content.  The implementation is as simple as it gets, and IMHO is the best solution for rendering iFrame content wrapped by the jQuery UI Dialog Widget.

The only this missing in the jQuery UI Frame Dialog Plugin was a way to provide a loading panel (eye candy) while the iFrame's source is loading.  You know the type - where an animated image is displayed while the content is acquired, loaded, and rendered and the animated image disappears when the the content is ready.

I made a few modification to the jQuery UI Frame Dialog Plugin to support the loading panel concept.  Essentially, I added a new property (loadingClass) to the options hash parameter.  The loadingClass property is a CSS class containing styles to apply to the jQuery Dialog Widget while the iFrame's content is being acquired, loaded, and rendered.  The following is an example of a CSS class used for the loadingClass parameter:
.loading-image { background: transparent url('assets/im/progress-indicator-alpha.gif') no-repeat center center; }
The following is the JavaScript used to open the dialog (initiated via an anchor):
$('#dialog_link').click(function(){
var $dialog =
   jQuery.FrameDialog.create({
      url: 'http://espn.go.com',
      loadingClass: 'loading-image',
      title: 'This is the Dialog\'s Title',
      width: 900,
      height: 600,
      autoOpen: false
   });
   $dialog.dialog('open');
   return false;
});
If you're interested, an online demo is located here: jQuery UI Frame Dialog Plugin with Loading Panel. The JavaScript file is accessible via View Source.

I wanted to notify the developer of my addition to the jQuery UI Frame Dialog Plugin.  So, I navigated to the plugin page, clicked the 'View Pending Feature Requests', successfully logged in with my account, and received the following error.  The crazy thing about this error, I keep getting this error if I navigate anywhere on the Plugins site while logged in.  Strange behavior!  Hopefully this is a temporary issue...


Thanks for reading...

23 comments:

radha said...

hi waldo,

where can i get plugin for jquery ui frame dialog ,please if you can post me @radhakrishna429@yahoo.com

tdryan said...

@radha - For some reason, the source for the plugin is no longer available. Try going to the demo page and download the source via 'view page source' or use one of the Firefox and/or Chrome extensions.

xknet said...

great article. this is the scenario:
A - main.html
click on a button on A, opens B - child.html
click on a button on B, opens C - cchild.html

C should be open from top (in this case from A).

Is it possible ?

Sam Stange said...

This post got me going in the right direction when using the jQuery UI dialog wasn't cutting it. Thanks!

bexdsm said...

thanks for your example! any idea how i can close the dialog from within the displayed page?

M. Kurniawan Y.H said...

To everyone

like xknet said
A - main.html
A have a textbox such as inpA
click on a button on A, opens
B - child.html

How to send a value from B to textbox on A (inpA) ?

Thanks.

tdryan said...

Hello xknet and M. Kurniawan Y.H. The two html files (main.html and child.html) must be in the same domain - this is required to prevent cross-site scripting and enforces SOP (single-origin policy). To fulfill a requirement such as yours, you would code the logic exactly how you would if you were using frames and wanted to pass values among the various frames. The following link contains logic using jQuery (not tested, only writing real quick) that will put you down the right track - Pass Values among frames/iframe using jQuery - untested - only a snippet. Hope this helps...

Yasen ® said...
This comment has been removed by the author.
Yasen ® said...
This comment has been removed by the author.
Yasen ® said...
This comment has been removed by the author.
Yasen ® said...
This comment has been removed by the author.
Yasen ® said...
This comment has been removed by the author.
Yasen ® said...

Hi Dan,
Your script looks amazing, good job. I was trying to modify my existing working modal dialog with iFrame to include your loading feature but I am having a hard time to do that. I do have link to your JS in my page header as well as your style example and GIF image..... just cant make script work, could you please have a quick look at my script. Thanks

[script type="text/javascript"]

function openNewInv(){
var apexSession = $v('pInstance');
var apexAppId = $v('pFlowId');
var assetNumber = $v('P3_ID');

$(function(){

vRuleBox = '[div id="InvBox" title="New Inventory Record"][iframe src="f?p='+apexAppId+':15:'+apexSession+'::NO:15:P15_ASSET_ID:'+assetNumber+'"width="630" height="360" title="Create Inventory Record" frameborder="no"][/iframe>[/div]'

$(document.body).append(vRuleBox);
$("#InvBox").dialog({
buttons:{"Cancel":function(){$(this).dialog("close");}}, stack: true,
modal: true,
width: 650,
resizable: false,
autoResize: true,
draggable: true,
close : function(){$("#InvBox").remove();
location.reload(true); }});

//To hide a button panel
$('.ui-dialog-buttonpane').hide();

});}
[/script]


P.S. all html tags are in [] has to be replaced with <>

....and forgot tom say, that on my parent page a have a button which calls "javascript:openNewInv();" to open modal.

tdryan said...

Hello Yasen: I don't know how much I can help. You're opening you dialog completely different than how the Frame Dialog plugin recommends (e.g. jQuery.FrameDialog.create). My recommendation is for you to look at the demo and view the source. The modified Frame Dialog plugin javascript file (jquery-framedialog-1.1.2.js) is what provides the necessary facilities to support the loading functionality. The demo view source also contains the dialog opener script via jQuery.FrameDialog.create. You will most likely need to rewrite you dialog setup and opening script via jQuery.FrameDialog.create.

Yasen ® said...

Hi, Dan, thanks for quick reply. I did all that (had a look on demo source page) did try to make my modifications...but it just does not work

tdryan said...

Start simple. Create a whole new html page; copy the code from the view source; and, make that work - this is completely independent of your work. Then try to slowly add your functionality and requirements in incremental steps. Test each step along the way to ensure that the results are what are expected. This will take time, but it should solve your issues.

tdryan said...

Yasen: post your email. I'll delete the comment with the email once i get it. I'll play around with your example and get back with you.

Yasen ® said...
This comment has been removed by a blog administrator.
tdryan said...

Yasen: I just sent you (via email) a solution to my interpretation of your requirement/issue. I hope that helps...

Yasen ® said...

wow, thanks a lot. Just got it and quickly teted it out. Works in your example....moved it into my app...does not work....hm....have to check it again.

Yasen ® said...

Hi Dan,
Sorry for bugging you again. I just wanted to show you what is happening to my app. I am using oracle apex and did inserd yor script (from your email) into online demo. The only change I've made is the URL variable, otherwise it is all the same...and it doesnt work...weird. With FireBug I am getting errors:
elem.document.body is null
elem.document.body[ "client" + name ] || docElemProp; jquery-1.5.2.js (line 8346)

and

jQuery.FrameDialog.create is not a function
close: function(event, ui){ f?p=32...61::YES (line 49)


Here is my workspace link and credentioal so u can see my script.

http://apex.oracle.com/pls/apex/f?p=32646
user: guest
psw: apex_demo

sreehari said...

HI,

Your post looks great.

I am trying to implement this in one of my projects. Is it possible to close this framedialog porgrammatically?

What i am trying to implement is like, from the content page, fire a function of parent and from ther e i am trying to close this modal dialog. Is it possible?

Thanks,
Sreehari

tdryan said...

Hello Sreehari:

Your desired functionality is absolutely possible; however, there are a few caveats. If you view the plugin's javascript, the comments contain the following:


* !!!!!!!!!! WARNING WARNING WARNING WARNING !!!!!!!!!!
* Modal must set the result from the same host address in order to access
* the parent for setting the result.
The reason for this is described as SOP - Same Origin Policy. This is a security limitation that requires the iFrame source (child) to be from the same origin as the parent initializer for the child to invoke functions on the parent (and vice versa).

If your need passes the SOP test, you would create a reference to the dialog on the parent page and use that reference from the child page to close the dialog. Since the plugin is essentially inheriting the jQuery UI dialog functionality, you would use the jQuery UI dialog 'close' method to close the dialog - just like closing the out-of-the-box jQuery UI dialog

The following is an untested snippet of what you might use:

<!-- Page Page -->

<script type="text/javascript">
var $myDialog = jQuery.FrameDialog.create({...});

var closeTheDialog(){
$myDialog.dialog("close");
}
</script>

<!-- Child Page -->
<!-- this assumes child page does not have a reference to the jQuery library -->

<button onclick="closeMe();">Close Me</button>

<script type="text/javascript">
// parent is the parent page that opened the dialog
// closeDialog is the function on the parent page
var closeMe = function(){
parent.closeDialog();
};
</script>