OK, time I contributed something slightly more substantial than vague ramblings.
It sometimes happens that an ASP.NET page containing dynamic content will be required to provide popup windows from which a user makes changes which cause the content on the parent page to be out of data - for example, you may have a DataGrid lists key elements of various record, but rather than editing these records in place as is provided for by the DataGrid, you provide a button which prompts a popup window to appear which users use for detailed editing. This may be done for several reasons, possibly even because your users simply would not be satisfied with the in-place editing experience. Or perhaps your edit process is dynamically building a list that is displayed on the parent page.
The problem is that you can happily perform your updates in the child window and close it, but the parent page will of course remain in its original state: any changes made in the child window will not be reflected until the page is refreshed. In other words, you have to trigger a postback. Asking people to hit “Refresh” after closing the child window would obviously be a user-hostile approach. Fortunately there are at least two possible solutions, depending on whether you need to avoid page validation and also on whether you need to target non-Microsoft browsers. The first, simplest and most browser-agnostic solution (at least it works with Netscape 7 as well as IE6) requires exactly one line of JavaScript:
window.opener.document.forms[0].submit();
The only drawback with this method is that if you have any Validators on the page, they will be triggered by the Submit.
The second approach is more messy, and does not work with browsers such as Netscape (because it relies on execScript), but it does allow you to generate a postback without triggering validation (I should warn you however that it does have “grotesque lame hack” written all over it, and would cause you to be sniggered at by Serious And Snooty People.) But here goes:
First, you add a control to the parent page that supports postback without validation. My personal preference is to use a LinkButton, give it a “display:none” style (note: don't try setting the control's Visible property to “false”, because that causes its HTML not to be rendered at all, which would Be A Bad Thing), and set its CausesValidation property to “false”. So you have an invisible non-validating LinkButton.
To trigger a PostBack event from the child page, you use the following JavaScript (assuming you are using a LinkButton called LinkButton1):
window.opener.execScript("__doPostBack('LinkButton1','')","JavaScript");
An easy way to test this sort of thing is to create an ASPX page that displays the current time on page load. It will be easy to see if a child window is causing the page to be refreshed, because the displayed time will be updated.
And that's that.
Addendum
I realised after posting the above that there are two questions that logically arise that I had forgotten to address
- Will Whidbey-I-mean-Visual-Studio-2005 validation groups take care of the issue of window.opener.forms[0].submit() triggering validation?
- Will any of this still work with the extra popup-related security in Windows XP SP2?
The answers are as follows:
- Sadly no (I tried it. I don't know how validation groups work under the covers so I can't say why. I can however say that they are nevertheless seriously wonderful )
- I have no idea, not having the SP2 beta. That's one of the reasons my coworkers and I are looking forward to many happy hours regression testing :-).
Update (or “Addendum #2“) : 19th July 2004
As people have rightly pointed out to me, a question I did not address properly above (because I was tired, lazy etc.) is “Fine, so where do I put the script?”. There are potential gotchas here, so it bears some explanation.
If you have a need to refresh the parent page it's reasonable to assume that as a result of some input on the child form, something has changed on the server that you would like to see reflected on the parent. Typically, the parent page might be displaying a data-bound list control of some sort, and you may be using a pop-up window to add or edit content that should be reflected in that list (a bulletin board application would be one example).
It is safe to assume therefore that in most cases you will be performing postbacks on the child form itself, after which you want a postback to occur on the parent form. The short answer to the question I asked myself above is that you should not attempt to attach your parent form postback triggering event (I think I will now have to execute myself for crimes against the English language) to the button (assuming it's a button - let's say “buttonesque object” and be safe) that you use to trigger the update of your child form. The safe way to do it is to have a “Save” (or “Add” or “Update” or whatever in the language of your choice) button (or buttony thing) that triggers the update of the child form, and have a separate Close button that you use to er, close the child form. The Javascript attached to that button would perform the submit or postback to the parent form and then execute a window.close() to close the child form.
e.g.
<INPUT id="ButtonClose" onclick="window.opener.document.forms[0].submit();window.close()" type="button" value="Close" name="ButtonClose">
Normally I would replace that inline code with the name of a Javascript function defined in a <script> block, but since I have doubts about that working with XP SP2 for an internet page I'm playing safe. Or safe-ish. However, it would be challenging to use the “__doPostBack” version without putting the code in a separate function (unless you like playing with nested quotes for hours on end).
One last thing - you may be wondering “What about modal windows?”. My personal view on that is that getting an ASPX page to work well as a modal window is not worth the pain and suffering it entails just to get a return value. And after all, if you need a client side return value on the parent page you can always just use a hidden field populated from the child (and the advantage there is that you can have more than one).
Additional Update 26th July 2004
Another point I forgot to mention is that these techniques obviously won't work if the data on the parent page that you want refreshed is only populated when the page is first loaded (for instance where you're displaying drop-down lists that will subsequently be reloaded automatically from ViewState). In those circumstances you'd be better off using the location.href approach that some people have mentioned (which is otherwise not the best choice IMO precisely because it does an initial page load, not a PostBack. But it's horses for courses.)
18 October 2004: Corrected error in first example of submit()