« So far, so good! | Main| Quick tip: How to prevent users from "backing up" to cached forms... »

Work-rounds, kludges, and hacks - oh my!

QuickImage   
Category
Bookmark : del.icio.us  Technorati  Digg This  Add To Furl  Add To YahooMyWeb  Add To Reddit  Add To NewsVine 


I am at a client site again this week, and while here I ran into two problems - and I wanted to share them with you, and the workarounds I came up with. Incidentally, both of these problems deal with Web/Domino development. The first problem concerns IE's window.showModalDialog method, and the other problem deals with document.forms[0].submit that doesn't submit.

Problem #1 - doing more with showModalDialog
In IE there is a method on the window object called showModalDialog. This method is similar to window.open, in that it allows you to launch a window as a dialog box. However, there are distinct differences. Window.open is a full-blown new browser window, and has all the functionality of a browser window; additionally it has properties such as window.opener, which provides access to the "parent" window object. This is extremely handy when creating very interactive dialog boxes that work with the parent document. The drawback to window.open is that the window it opens is "modeless", i.e. the parent window is independent of the dialog window, meaning the user can click away from the dialog and change the parent window, close it, etc. This can really mess up your workflow. I needed to have a "modal" dialog window that acts like a Notes dialog box, i.e. the user must close/clear the dialog before doing anything to the parent window. I found the window.showModalDialog method - and then I found some limitations with it.

Window.showModalDialog is great in that it provides a truly modal dialog, but it has some serious limitations when wanting to create interactive dialogs. The best way to think of window.showModalDialog is that it is simply a dialog - it gathers values and can return a value. It does not have any "real" relationship to the calling window, except that it returns a single value to the calling code. It does not have a window.opener property, and as stated earlier, when called it does not provide a handle to the dialog window through the calling code - it simply provides a single, scalar return value once the box is closed. This can seriously mess up your code if you have interactive dialogs. Another problem I found with showModalDialog - any and all links in the dialog, including "javascript:function" links, launch into a new window - not in the dialog window. This is also undesired behavior. So, how can you get around this? Well, since we're already writing IE-specific code, let's go ahead and use another IE-specific call - iFrames.

Solution #1 - use an iframe
I did some scrounging around on the net, and found that the best solution to this dilemma is to use an iframe, and load your dialog into that iframe. Translating this to Domino development, here's how I implemented this. I created a new form called dialogOpener. In this form I have a simple, single line of passthru HTML:

  <iframe name="receivedDlg" width="100%" height="100%" src="/<computed text>/your_dlg?OpenForm&<computed text>" frameborder="0"></iframe>

The first computed text computes the relative path to the db, and the second computed text pulls the query string values off of the URL and passes them on to the "real" dialog form. By loading the "real" dialog form into the iframe, I get all the functionality that I want and I get a modal dialog box. But hold on - we do need to make a minor modification to our javascript in our dialog form. Remember that I said earlier that the showModalDialog method doesn't provide a window.opener object? Here's how you get around this. One of the parameters of the showModalDialog method is the dialogArguments parameter (refer to the link above for syntax). This allows you to pass an entity - a value, an object, etc. - to the modal dialog for processing. Well, you can pass the calling window to the modal dialog by using the self object, like this:

      window.showModalDialog(your_url, self, your_args)

And then in the JSHeader of your dialog form you can retrieve the window.opener like this:

        if (window.opener) {
                parentdoc = window.opener.document
        } else {
                var dargs = window.dialogArguments;
                parentdoc = dargs.document
        };

This code checks for an opener object, and if one isn't found the object is retrieved from the dialogArguments property, which contains the self object passed in the showModalDialog method. Now your code will work as you originally designed it, with the added bonus of being a modal dialog.

The second problem seems to be related to the first solution - but I can't prove this for sure. Let's talk about problem #2.

Problem #2 - the document.forms[0].submit() that doesn't
Now I don't know if this problem is related to the solution previously described, but in any case it is a problem that was extremely frustrating. I found that my document.forms[0].submit() call was intermittent in my dialog boxes. It would work, and then it wouldn't, and then it would start working again, and there was no rhyme nor reason to when it would and wouldn't work. I did some searching on the net and found that others have encountered this as well. It appears that Domino can ignore the document.forms[0].submit() call when it is called from a dialog. The javascript code continues to run as if it were successful, but the changes made aren't saved to the document. The workaround that seems to work best is to replace the javascript submit() call with @Command([FileSave]); @Command([FileCloseWindow]). This works well as it consistently and reliably saves the dialog values to the document, but this workaround doesn't solve all my problems.

In my dialog box I am saving the values to a document, but also updating values in the parent window's document and then closing the dialog window. So I need the save to values, I need to update the parent window document, and I need to close the dialog window. I have a validate() javascript function call that needs to validate the dialog before saving and closing as well. I tried various combinations of window.close() in the javascript, all to no avail. So then it was time to venture into Kludgeland.

Solution #2 - getting weird with $$Return
I finally solved this by doing a couple of things. First, I placed my validate() function call in the onSubmit event - the validate() function returns a true/false, which in turn will stop the processing of the save/close. I then created a new form called dialogCloser. In this form I have a simple window.close() in the onLoad event. I then call the dialogCloser form in a $$Return field on my dialog form. So, if the dialog passes validation the dialogCloser form is launched, which immediately closes the dialog.

Conclusion
Yeah, I know these aren't pretty, but they got the job done, and I got the functionality that I and my client want. I wanted to make these available to hopefully save someone else the frustrations of figuring all of this out. Incidentally, if you have and similar problems and solved them differently, I would love to hear about it.

Enjoy!

Rock

**He looks like a dwarf who was dipped in a barrel of pubic hair. -- Boy George on Prince

Comments

1 - Hi all,

I've been reading many articles and blogs about this problem.
The iframe solution seems to be the most common workaround.

But this solution (like Leon said) was the simplest and it worked for me:
putting <base TARGET="_self"> in the head section of the page.

Dangeriz

2 - Rock:
Get this book....
http://www.amazon.com/exec/obidos/tg/detail/-/1565924940/qid=1062077490/sr=8-1/ref=sr_8_1/002-1247701-5133653?v=glance&s=books&n=507846

Covering HTML, JavaScript, DOM and CSS, it is a must have for any web application developer.
Best of Luck.

3 - I have found an alternative to <BASE target="_self">

in the initialise code (via OnLoad) place this code
window.name='fred';

then in the html form tag use: <FORM ID=frm NAME=frm ... TARGET="fred"> you'll find that when you submit the form with document.frm.submit(); it will load into the same dialog.

the only problem i've found is that the title of the dialog is lost - any ideas how to rectify this?

4 - add <base target="_self"> to the <head> section of the html source, the problem "Another problem I found with showModalDialog - any and all links in the dialog, including "javascript:function" links, launch into a new window - not in the dialog window" will be resolved.

5 - **sigh**, you're probably right, Nathan. I know you're right that I'm a "Notes developer working on the web". I need to learn more about CSS - and the stuff I see put out by you and others makes me realize this more every day. Do you have any suggestions for places/books/etc. to get started?

Rock

6 - Is there a way to handle more than one return values that a web site (opened in a window.showModalDialog) be handled in javascript, without any delimiter ?

7 - if you want to open a new window and have it stay on top until someone clicks a close button or something, you can pop this into the body tag in a form:

"onBlur=\'self.focus()\'"

so then the form would crank out something like:

<body onBlur='self.focus()'>

that will keep the window on top and basically force the user to do something with it (unless they have javascript turned off). might be an easier way to go, depending on your workflow.

i've worked with the showModalDialog thing, i thought it was pretty darn cool. of course, it was on an intranet where IE is the supported browser. but still, it did exactly what i wanted it / needed it to do. i guess its all in the requirements...

8 - hi all i have a problem of using window.opener.document.forms[formname].elements[fieldname].value='somevalue' in window.showmodaldialog() method.
problem is

i have a parent page with one text box and button. clicking on the button the page will open using showmodaldialog() method.and i have some set of values in the child window. if i add one value the value should return to the parent window.

but i was not able to do this the child window value is stored in the window.opener.document.forms['formname'].elements['fieldname'].value='value';

any solution for this problem
sathish

9 - I don't care what all those guys who criticized your methods on #1 say. I used it and it works in my situation like a charm.
I didn't even need the iframe, just had to get a reference to the window opener to make what I already had work right.


Some people just need to relax a little and realize there is always a situation that merits the use of a bit of unorthodox code.

10 - Nice article man ... Prasanth

11 - just thought I should let you guys know that you don't need to use an IFrame. Just put <base target="_self"/> in all the pages you link off in dialog windows. Problem solved, and things can run as per normal without any kludgy workarounds. The opener stuff is useful I suppose, but if all the data's on the server as is common in server applications then this shouldn't be a problem. Oh, and I love the live preview. Very cool!

Best regards

Leon

12 - all of you are right but wrong . I am not a notes developer at all. I do ASP.NET and am a web development expert. you will find a lot of situation where using CSS and DIV tags is not sufficient. I write apps where I need to open lookup pages a lot and then pass back the values back to the opening page. What you guys are talking about works extremely well if you mainly need to show static content, otherwise if you want to show dynamic content with a lot of server side code in those popups, you are better of using Rocky Oliver's method.


...can a fool who knows their wisdom still be called fool...

13 - I have a parent form which opens a child window using showModalDialog box. when i press close button on child window, it gives error on some I.E. browsers. i have written following code on close button. it is giving __eventTarget is not a null or an object.

function closePopup(formName, eventTarget)
{
if (formName != null && eventTarget != null)
{
var da = window.dialogArguments;
var theform;
theform = da.document.forms[formName];
theform.__eventTarget.value = eventTarget;
theform.__eventArguments.value = "frompopup";
theform.submit();
}
window.close();
}


Basically on some browsers theform variable is giving output as undefined. i could not resolve this problem.

If anyone knows the solution, please reply it to me

Thanks

14 - By the way, iframe isn't an IE specific tag - it's part of the HTML4 standard: http://www.w3.org/TR/html4/present/frames.html#h-16.5

15 - @Sathish - that's what this blog entry is about! You have to use the iFrame method I describe above to get the parent (opener) document handle - showModalDialog doesn't have one.

Rock

16 -

17 - Danny Goodman's "Dynamic HTML: the Definitive Reference 2nd Edition" (O'Reilly). If it ain't there, it ain't on the web -- and Danny's good enough to let you know what works in which browser with what limitations consistently (and what's standard and what's proprietary, as well). There is simply no better reference for HTML, CSS and JavaScript combined on the planet.

For a CSS web reference, try http://www.alistapart.com.

18 - Hi
I tried <body onBlur='self.focus()'> . The problem I face is that I have 2 drop down lists in my modal popup window & I cannot select anything from the dropdown. Is there any way to olve this issue ?

Thanks
SD.

19 - gs

20 - you need to get yourself the Javascript and HTML w/ CSS cards from Visibone (http://www.visibone.com). They are the best thing ever. Show all of the parameters, what they do, and which browser they work in.

And, with looking at my Visibone chart, iframe and ilayer are both part of the W3.org definition, but iframe is not supported in IE and ilayer is Netscape 6 and under only. Mozilla seems to support both.


21 - oops, I'm sorry I used a wrong Url as my Hompage, and I found that Dangeriz has given the idea on #23.

22 - Good work-arounds!!! This has helped me.
Keep the sharing spirit on.

- thanks
vishal

23 - How can I highlight text in a window opened by showModalDialog() method? Any ideas? Thanks in advance!

24 - @Lak - glad to be of help - and thanks for stopping by!

Rock

25 - Anton - thanks for the "refining" of the idea - I like it!

"wise fool" - thanks for the support - and I agree with you

Oh, and I love that this post keeps getting traffic from Experts Exchange. Tres' kewl...

Rock

26 - onclick="window.showModalDialog('URL');window.location.reload();)

makes the opener window refreh after the modal dialog closed..

27 - <html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>New Page 1</title>
<SCRIPT language='javaScript' src="validate.js"></script>
<script language='javascript'>

var confirmMessage = '';
var confirmFlag = false;
function checkFocus()
{
if (window.navigator.appVersion.indexOf("MSIE")==-1)
{
if ( modalWin != null && !modalWin.closed )
{
self.blur();
modalWin.focus();
}
}
}

function deleteBul()
{
var del = openConfirmDialog('Are you sure you want to delete this building?');
if (del)
{
alert('weclome');// i need to inter
// here when press ok from the
//ConfirmDialogE.html
}
}

function openConfirmDialog(message)
{
confirmMessage = message;
confirmFlag = false;
//window.showModalDialog("ConfirmDialogE.html", window, "dialogWidth:375px;dialogHeight:150px;scroll:no;resizable:no;status:no;help:no;");
window.open("ConfirmDialogE.html", '','dialogWidth:400px;dialogHeight:150px;scroll:no;resizable:no;status:no;help:no;');
return confirmFlag;
}

</script>
</head>
<body onload="checkFocus();">
<from id='frm'>
<div id='save' ></div>
<table width="188">
<tr>
<td>window.opener();</td>
<td class="tableCellNormal" width='14%'>
<A href="javascript:deleteBul()" >Delete</A>
</td>
</tr>
</table>
</from>
</body>
</html>


ConfirmDialogE.html is


<html>
<head><title>Confirm</title>
<script language='javascript'>
function ok(){
//dialogArguments.confirmFlag = true;
opener.confirmFlag = true;
window.close();
}
function cancel() {
//dialogArguments.confirmFlag = false;
opener.confirmFlag = false;
window.close();
}
function confirmMessage(){
document.getElementById('validationTD').innerHTML =""+ opener.confirmMessage;
}

</SCRIPT>
</head>
<body onload='confirmMessage()'>
<table width="100%" border="0" align="center" dir=ltr>
<tr>
<td width="12%" align="left"><img src="QuestionMark.jpg" width="54" height="53"></td>
<td width="88%" class ='StanderdFont' align="center" id="validationTD">&nbsp;</td>
</tr>
<tr>
<td colspan="2" class='StanderdFont' align='center' dir=ltr height='75%' valign=top >&nbsp;</td>
</tr>
<tr align="center">
<td colspan="2">
<img style="CURSOR:hand" src="yes.jpg" border=0 onclick='ok()' >&nbsp;
<img style="CURSOR:hand" src="no.jpg" border=0 onclick='cancel()'>
</td>
</tr>
</table>
</body>
</html>


please help me????


28 - Hi guys. I had a strange problem with modal dialogs: I can't pass back returnValue if the dialog url is something like "javascript:someJScode". This seems to be a security issue fixed in IE 6. Does anybody know something more about this?

29 - Thx for your Solution#1, becase i got same problem.
That methods is so powerful. ^^

30 - ShowModalDialog? Rock... full stop, man. IE-proprietary method with a bad implementation. Why are you even bothering?

Do you know why there isn't a modal dialog in the W3C standards? Because they're a bad design decision in the first place. You're thinking like a Notes developer working on the web -- stop that!

If you really want to present something like that, make a hidden DIV that has the info you want, then use CSS-P to absolute position it on the page at the top Z-index. Make yourself an artificial "OK" button that just hides the DIV again. *That's* web development. :)

31 - Hi All,

Nice to see a place where people discussing something related to my problem...sir i want a solution for this...hope you people can find it out.

My form is containing an Iframe and it is opening a dialog window... my problem is i want to refresh the parentform of that iframe on submit of that dialogwindow....i am able to refresh the iframe but i want to get a hold of iframe and refresh its parent.......

can you please help me.... .....

chaitu

32 - Boy is this is sore subject with me. The number of poorly defined or just downright stupid standards implemented with an eye toward corruption or usurpation (is that a word?) rather than any genuine interest in making a good working environment is revolting.

More on this later.

33 - If you're ever interested in a CSS editor, I would recommend TopStyle by Bradsoft. I've been using it recently and it's well worth the money. It has a built in WC3 HTML integrator, rule enforcement based on the CSS Level you choose, netscape and ie preview, much much more.

http://www.bradsoft.com/topstyle/

34 -

35 - Hi !
It is very good work around to use Iframe, but iam not able to close this window using document.close()

36 - The ultimate way to do dialogs is CSS and DIV. ProjectDX features some nice examples (tabbed dialog, calendar). Add iFrame and you can open other sources. I played a lot with HTML-DOM lately. You can do cool things like create a widget that makes editable tables (the thing where you have 4 multivalue fields in Notes and it shows as a table with edit/append/delete a row and update the type=hidden fields directly. My learning source for that stuff is http://www.faqts.com

37 - hi Domino guys,

unfortunately this base tag does not help in Domino environment because of the javascript generated by Domino. Thank you Rocky for the good workaround, just one improvement to avoid dialogCloser form:

1. make an ERRORS_CFD field that makes server side checks

2. make submit button like this
@Command( [FileSave] );
@If( ERRORS_CFD = ""; @Command( [FileCloseWindow] ); "" )

3. put $$Return field like this
@If( ERRORS_CFD = "";
"<script>window.dialogArguments.RETURN_FIELD.value = 'okay'; window.close()</script>";
"" )

Meet Rocky

Rock - February 2010
Rocky Oliver
If you see me at a conference, please stop me and say hi!

Calendar

Search

Categories

Proudly Employed By

Wofkflow Studios

Thawte Notary

Thawte Web of Trust Notary

LOTUS GEEK gear

Social Networking


Add to Technorati Favorites

View Rocky Oliver's profile on LinkedIn

Rocky  Oliver

LotusGeek Blog Roll

Why display a blog roll when Planet Lotus does it so much better?

Dilbert

Buy my book!

Blog Buttons

Atheist - Unitarian - Humanist

Poker Players Alliance