Tuesday, November 29, 2005

 

Work Around for Javascript Reload Requiring "Retry" Click

Problem

Displayed on my currently opened browser window I have Datagrid / Gridview cotaining a list of editable records, 1 dropdown containing values to filter the data displayed in the grid, and 1 "Go" button to update the grid based on the selected value in the dropdown. When you click the "Edit" hyperlink for that record, a child browser window pops up (using javascript) an editable form populated with the values for that record and a "Save" button. When the "Save" button is clicked, I want the following to occur:

1. Save changes to database.
2. Close open child window containing editable form.
3. Refresh parent browser window containing Datagrid / Gridview so that the changes to the data is displayed without changing the selection in the dropdown filter.

At first glance, this would seem like an easy task. I use a .js file containing a group of javascript functions that handle repeated tasks such as opening and closing pop-up windows. To open the above referenced child window I would call the window.open() method. When closing a child window, if I would like to refresh the parent window, I would normally use code similar to the following:

C#



string script = @"
<script language="
"javascript"">
ClosePage();
</script>;
"
;

Page.ClientScript.RegisterStartupScript(typeof(Page), 'myJScript1', script);



Javascript



<script language="javascript">
// Close parent page.
function ClosePage()
{
if(opener != null)
{
// Redirect parent window to it's current url, giving
// the illusion of a refresh button click.
opener.location.href = opener.location.href;
}
// Close this window.
close();
}
</script>


As you can see the code simply redirects the document to it's current URL. A mock refresh. This works great when all the data you need is in the query string or stored in session variables. Unfortunately, if I 'refresh' in this manner the dropdownlist on the page resets back to the default select value. This breaks above requirement #3 "changes to the data is displayed without changing the selection in the dropdown filter".

I know that if I click the browser's refresh button, after a post-back, the dropdown remains the same. So I do some research and learn that I can call the parent page's javascript reload() method from the child page like so:

opener.location.reload(false);

So now, I replace "opener.location.href = opener.location.href;" with "opener.location.reload(false);" and I test it out. First, I select an item from the dropdown other than the default item. Second, I click the "Go" button. The page now displays a list of result records. Third, I click on one of the records, which opens a new window containing the details of the selected record. I make a small change to the record and click "Save". The detail/child window closes and the parent page begins to refresh. So far, so good. But wait...what is this?

Retry

The dreaded "The page cannot be refreshed without resending the information. Click Retry to send the information again" retry box. This will never do.

Solution

To refresh the data on an opener/parent (hereafter to be called "opener) window without tripping the the "retry box" trap, I used the following solution.

Instead of calling the reload() javascript function, I created a javascript function that calls the opener's submit() function. The child page can call this function after it's own "Save" button has been clicked. This will submit the opener page, rather than reloading it, circumventing the "retry box". The Page_Load event handler checks to see if the submit() function was called and executes the appropriate code to "refresh" the data on the page.

Add the following hidden field to the opener page:



<input id="hdnRefreshData" runat="server" type="hidden" value="0" />


Add the following javascript to the opener page:



<script language="javascript">
function RefreshMyData()
{
//alert('RefreshMyData');
var myHdnRefreshData = document.getElementById(<%= "'" + hdnRefreshData.ClientID + "'" %>);
myHdnRefreshData.value = '1';
window.document.forms[0].submit();
}
</script>


Add the following C# code to the Page_Load event handler of the opener page:



if (IsPostBack)
{
// When the FileTimeEdit.aspx's "Save" button is clicked, it
// calls the RefreshMyData() javascript function on FileTim.ascx
// which sets the value of the hdnRefreshData control and calls this
// form's submit function. I catch the submit request here.
if (hdnRefreshData.Value == "1")
{
// refresh data
FillPagingGrid();
// reset value of hidden field so it is not called when "Go" button
// is clicked.
hdnRefreshData.Value = "0";
}
}


Add this code to the child window's Save button's click event handler:



// Call javascript to close this window and call parent page function to
// refresh it's data, which may have changed with this save.
RegisterScript(@"opener.RefreshMyData();
ClosePage()"
);


I hope this solution works as well for you as it did for me.

Update (04/25/06): Sai pointed out that I make a reference to a function called "RegisterScript()", but I do not provide the code for it. So, here it is:



/// <summary>
/// Method to register javascript on web page.
/// </summary>
/// <param name="method"></param>
public void RegisterScript(string method)
{
string script = @"
<script language="
"javascript"">
<!--
{0};
//-->
</script>
"
;

Page.ClientScript.RegisterStartupScript(typeof(Page), method, string.Format(script, method));

}


Thanks Sai.

 

The Article of the Week 4

Title
Daily Builds Are Your Friend

Author
Joel Spolsky

Description
This weeks article expands on the idea of daily builds, which we touched on in last week's article. Joel describes the need for daily builds as well as some ideas on how to implement them properly. The article is very short.

While reading the article, keep in mind that daily builds may not be suitable for all of our applications, but for your big ones, it could increase your productivity and the quality of your end product.

Enjoy.


Tuesday, November 22, 2005

 

The Article of the Week 3

Title
The Joel Test: 12 Steps to Better Code

Author
Joel Spolsky

Description
The Joel Test contains a list of 12 steps to rate the quality of the software development. I don't see this as a list of requirements, but as steps towards being more efficient, and making programmers lives easier.

Our team has already taken 7 of the twelve steps:

1. Do you use source control?
4. Do you have a bug database?
5. Do you fix bugs before writing new code?
6. Do you have an up-to-date schedule?
7. Do you have a spec?
9. Do you use the best tools money can buy?
10. Do you have testers?

We plan on discussing the remaining steps to see if we all believe they are worth implementing, to what extent, and how to go about doing it:

2. Can you make a build in one step?
3. Do you make daily builds?
8. Do programmers have quiet working conditions?
11. Do new candidates write code during their interview?
12. Do you do hallway usability testing?

Because we work on so many different applications, step 3 (Do you make daily builds?) may be overkill for our team, but I think that it would make sense to build and run automated tests the day you make any changes to an application and check the changes into source safe. That seems like a big job now, but if QA guy keeps cranking out the automated tests, and we implement step 2 (Can you make a build in one step?) as a standard process, it could easily be a reality. There are many tools available that can assist us towards these steps. Some, like the NAnt build tool, are free.

Step 11 (Do new candidates write code during their interview?) nay be something to keep in mind going forward with any new hires, or for when we interview applicants for internships.

I like the idea of step 12 (Do you do hallway usability testing?), which, in a nutshell, is grabbing the next person who walks by your cubicle, pull them in, and giving them the choice of conducting usability tests on your latest app, or drinking the QA guy's coffee (you can cut it with a knife).

Currently we are in cubicles, but If our dream of being able to work remotely comes true, step 8 (Do programmers have quiet working conditions?) may become a reality.

Discuss why or why not, and how or how not, we should implement the 12 steps that Joel outlines. I would be interested in your thoughts and experiences regarding them.

Tuesday, November 15, 2005

 

The Article of the Week 2

Title
Human Task Switches Considered Harmful

Author
Joel Spolsky

Description
The article attempts and succeeds to get across the idea that alternating between two tasks does not get either one done sooner.

My favorite quote from the essay is:
"have you ever noticed that you can assign one job to one person, and they'll do
a great job, but if you assign two jobs to that person, they won't really
get anything done?"


This enlightening essay applies to a broad audience. I would recommend sharing it with as many people as possible. Not just programmers.

Monday, November 07, 2005

 

The Article of the Week 1

I have been recommending one article/essay a week to my co-workers, with positive results. So I have decided to expand my audience and post my recommendations to my blog.

The articles/essays you see posted under Article of the Week will give you a chance to read short writings that I have found valuable to my daily process, for sharing new ideas, and for stimulating creative discussion between co-workers.

I will try to keep the recommended material as short and as relevant as possible. Now, on to the Article of the Week.

Title
Craftsmanship

Author
Joel Spolsky

Description
Joel describes why he believes that programming is design and not craftsmanship. He defines design as "that nebulous area where you can add value faster than you add cost." Whereas craftsmanship is when you do something rare that makes your product stand out. However, doing something rare takes a lot of time and therefore is very expensive.

For this reason, you do not see much craftsmanship involved in solutions developed to be utilized in-house. This was an important idea for me. 90% of the solutions I work on are created for in-house use. I used to spend a lot of time trying to determine the "best" practices to implement a solution. Unfortunately this would entail much procrastination on my part.

I now realize that if the solution I am working on is only used in-house, and by one person, once a week (if that often), it probably makes more sense to complete it as quickly as possible, without spending too much time worrying about the "best" way. Save those for projects where they will make a difference. Like websites being accessed by users outside of your company, or applications that are being used by many users on a daily basis for mission critical tasks.

Content copyright ©2003-2006 Tod Birdsall