Showing posts with label AJAX. Show all posts
Showing posts with label AJAX. Show all posts
Friday, September 18, 2009
Frustrating Deployment Experience!
I've deployed a few simple AJAX-enabled web pages to a local server that is accessed through the Internet by just two people: me & a client.
When running locally in the VS2008 environment it works perfectly fine but when accessed through this server there are frequent and mysterious timeouts. There appears to be no pattern to when & why they occur. Sometimes I get strange errors with codes in the 40000 & 50000 range. Other times it just hangs. There is so little load on this server that I do not understand why this is occurring.
I suspect this is an AJAX related problem but am not sure of that. I'm wondering if anyone else has experienced something similar and might have some tips about how to resolve it?
When running locally in the VS2008 environment it works perfectly fine but when accessed through this server there are frequent and mysterious timeouts. There appears to be no pattern to when & why they occur. Sometimes I get strange errors with codes in the 40000 & 50000 range. Other times it just hangs. There is so little load on this server that I do not understand why this is occurring.
I suspect this is an AJAX related problem but am not sure of that. I'm wondering if anyone else has experienced something similar and might have some tips about how to resolve it?
Saturday, May 9, 2009
Using ThickBox with Server-side Buttons
For a while now I've been looking for a jQuery equivalent to the Modal Popup Extender. Two key requirements were:
string script = "$(document).ready(function() {tb_show('Sample Title', '#TB_inline?height=120&width=300&inlineId=sampleContent', null);});";
ScriptManager.RegisterStartupScript(Page, typeof(Page), "", script, true);
But the second requirement proved much more difficult. It seemed that no matter which open source dialog box I tried, it would just not allow server-side events to be fired.
Eventually though, through the help of ASP.Net user PNasser, I found a solution! The key was to add a simple Javascript function call to each ASP.Net button in the dialog box:
Which then calls this:
function doPostBack(element) {
tb_remove();
setTimeout('__doPostBack(\'' + element.name + '\',\'\')', 500);
}
That's it! What's happening is that first the call is made to the ThickBox to remove itself. This is precisely the same function that's called when you click on "close" in its title bar or press "Esc".

Then a postback is explicitly called via the __doPostBack function. But it isn't called immediately. Instead, it's executed after a 500ms delay. I don't precisely know the reason why the delay is necessary but am guessing that it provides the ThickBox enough time to fade out and dispose of itself. I experimented with the delay time and found on my computer that as low as 300ms worked. Less than that though and a full postback occurred, which is not the effect one wants on an AJAX-enabled page!
I've created a little demonstration project which you can download here.
- It had to be able to be called from server-side code.
- The dialog box itself had to have ASP.Net buttons.
string script = "$(document).ready(function() {tb_show('Sample Title', '#TB_inline?height=120&width=300&inlineId=sampleContent', null);});";
ScriptManager.RegisterStartupScript(Page, typeof(Page), "", script, true);
But the second requirement proved much more difficult. It seemed that no matter which open source dialog box I tried, it would just not allow server-side events to be fired.
Eventually though, through the help of ASP.Net user PNasser, I found a solution! The key was to add a simple Javascript function call to each ASP.Net button in the dialog box:
OnClientClick="doPostBack(this);"
Which then calls this:
function doPostBack(element) {
tb_remove();
setTimeout('__doPostBack(\'' + element.name + '\',\'\')', 500);
}
That's it! What's happening is that first the call is made to the ThickBox to remove itself. This is precisely the same function that's called when you click on "close" in its title bar or press "Esc".
Then a postback is explicitly called via the __doPostBack function. But it isn't called immediately. Instead, it's executed after a 500ms delay. I don't precisely know the reason why the delay is necessary but am guessing that it provides the ThickBox enough time to fade out and dispose of itself. I experimented with the delay time and found on my computer that as low as 300ms worked. Less than that though and a full postback occurred, which is not the effect one wants on an AJAX-enabled page!
I've created a little demonstration project which you can download here.
Labels:
AJAX,
ASP.net,
dialog box,
JavaScript,
jQuery,
server-side,
ThickBox
Sunday, October 26, 2008
Visible = false vs. display:none
I learned a painful little lesson today which hopefully will benefit others.
Most every ASP.Net control has a Visible property, which can be set to either 'true' or 'false'. If you've ever set it to 'false' and look at how it's rendered, you'll see this HTML property: style="display:none"
But when you're using the AJAX Control Toolkit, the two ways of hiding a control are not always equal.
For example, when I use the ModalPopupExtender to display a dialog box, I frequently define the TargetControlID with a dummy button. Why? So that I can programmatically control when the dialog box is displayed. Here's a very straightfoward example:



The only reason that buttonDummy exists is because the ModalPopupExtender must have a TargetControlID defined. And since you don't want the user to see this dummy button, you need to hide it. But doing so by setting Visible="false" internally seems to mess up the logic of the ModalPopupExtender. When you're expecting the dialog box to display, the code runs but nothing happens.
Most every ASP.Net control has a Visible property, which can be set to either 'true' or 'false'. If you've ever set it to 'false' and look at how it's rendered, you'll see this HTML property: style="display:none"
But when you're using the AJAX Control Toolkit, the two ways of hiding a control are not always equal.
For example, when I use the ModalPopupExtender to display a dialog box, I frequently define the TargetControlID with a dummy button. Why? So that I can programmatically control when the dialog box is displayed. Here's a very straightfoward example:
The only reason that buttonDummy exists is because the ModalPopupExtender must have a TargetControlID defined. And since you don't want the user to see this dummy button, you need to hide it. But doing so by setting Visible="false" internally seems to mess up the logic of the ModalPopupExtender. When you're expecting the dialog box to display, the code runs but nothing happens.
Sunday, August 31, 2008
Using SetFocus in an AJAX Panel
If you have a TextBox on a regular ASP.net web page then you can force the initial focus to it with code such as this:
SetFocus(textBox);
But if your web page is AJAX enabled then this won't work. But the following code will:
ScriptManager.GetCurrent(this).SetFocus(textBox);
SetFocus(textBox);
But if your web page is AJAX enabled then this won't work. But the following code will:
ScriptManager.GetCurrent(this).SetFocus(textBox);
Monday, May 5, 2008
Manually Wiring Up the AJAX UpdateProgress Control
A common feature of AJAX-enabled pages is to have an animated "Please Wait" image appear while the partial page update is occurring. With ASP.Net this is implemented very easily. Here's an example:<asp:updateprogress id="UpdateProgress1" runat="server" visible="true" associatedupdatepanelid="UpdatePanel1"></asp:updateprogress></span>
<span > <progresstemplate></progresstemplate></span>
<span > <div class="progress">
<span > <img src="http://blogger.com/Images/Progress/progress_indicator.gif" alt="" /></span>
<span >
</span>
<span > Please Wait</span>
<span > </span></div></span>
<span > </span>
<span > </span>
<span > <asp:updatepanel id="UpdatePanel1" runat="server"></asp:updatepanel></span>
<span > <contenttemplate></contenttemplate></span>
<span > <%-- Content goes here --%></span>
<span > </span>
<span > </span>
</span>
That's all there's supposed to be to it. Refer the UpdateProgress control to the UpdatePanel and it's just supposed to work. My experience hasn't been quite so straightforward. The progress indicator would appear some of the time, but not every time. The reason for this I do not know but my work last week to correctly warn a user when they're leaving a page early taught me about the AJAX Javascript events "Initialize Request" and "End Request". Today I used them to improve the consistency of the Progress Indicator:
<script type="text/javascript">
Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(InitializeRequestHandler);
function InitializeRequestHandler(sender, eventArgs)
{
document.getElementById('<%=UpdateProgress1.ClientID%>').style.display = 'block';
}
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);
function EndRequestHandler(sender, eventArgs)
{
document.getElementById('<%=UpdateProgress1.ClientID%>').style.display = 'none';
}
</script>
After adding this code, everything now works beautifully. The Progress Indicator displays every time, not just some of the time!
Thursday, May 1, 2008
Warning the User About Prematurely Leaving a Web Page - Update
My earlier posting illustrated how one can easily trap the beforeunload event and decide whether to display a message to the user that exiting the page without first saving the data will result in all unsaved work being lost.
But then I discovered that it was not working properly on my web page. Whenever any of the command buttons - Add, Delete, Move, and Save - were pressed, beforeunload was fired and I would be warned about leaving the page.
This was most confusing because I knew I wasn't leaving the page! But I intuitively knew that there's always a logical explanation so it was just a matter to find it. As I frequently do, I posted a few messages on the ASP.Net Forums. A very bright developer from Portugal named Luis Abreu responded and provided me some sample code. I ran it and his code ran perfectly. So why on earth was mine not working?
On my page I added a simple button, like Luis had done, to force a partial page postback. Pressing it did NOT force the beforeunload event to fire! WTF?!?
I stared at my web page for some time and suddenly realized what the problem was. Those aforementioned command buttons are not sitting directly on the page but instead reside in a Draggable Panel. Also, the Move button causes a Modal Panel to appear. While both of these panels are technically "on the same page", from the perspective of beforeunload I suppose they are not.
So now, when any of the buttons are pressed, the first thing that occurs is that the beforeunload handler is turned off. But it had to be reactivated. To accomplish this I added a call to this function at the end of each button's server-side method:
private void ToggleBeforeUnload(bool onOff)
{
ScriptManager.RegisterClientScriptBlock(this, typeof(Page), "toggleBeforeUnload", "ToggleBeforeUnload(" + onOff.ToString().ToLower() + ");", true);
}
It calls the same JavaScript function described earlier. And sure enough, it works perfectly!
Incidentally, blessed is the Internet for helping out developers! I distinctly remember the days when there was no Internet. I'm absolutely convinced that it has dramatically improved the productivity and learning curve of developers around the world.
But then I discovered that it was not working properly on my web page. Whenever any of the command buttons - Add, Delete, Move, and Save - were pressed, beforeunload was fired and I would be warned about leaving the page.
This was most confusing because I knew I wasn't leaving the page! But I intuitively knew that there's always a logical explanation so it was just a matter to find it. As I frequently do, I posted a few messages on the ASP.Net Forums. A very bright developer from Portugal named Luis Abreu responded and provided me some sample code. I ran it and his code ran perfectly. So why on earth was mine not working?On my page I added a simple button, like Luis had done, to force a partial page postback. Pressing it did NOT force the beforeunload event to fire! WTF?!?
I stared at my web page for some time and suddenly realized what the problem was. Those aforementioned command buttons are not sitting directly on the page but instead reside in a Draggable Panel. Also, the Move button causes a Modal Panel to appear. While both of these panels are technically "on the same page", from the perspective of beforeunload I suppose they are not.
So what to do? I thought about it for a second and realized that with each of these buttons I could use the local 'OnClientClick' event to temporarily disable the beforeunload check. With this goal in mind I added this JavaScript function:
function ToggleBeforeUnload(onOff)
{
if (onOff == true)
{
window.onbeforeunload = ConfirmExit; // Activate beforeunload event handler
}
else
{
window.onbeforeunload = null;
}
}
So now, when any of the buttons are pressed, the first thing that occurs is that the beforeunload handler is turned off. But it had to be reactivated. To accomplish this I added a call to this function at the end of each button's server-side method:
private void ToggleBeforeUnload(bool onOff)
{
ScriptManager.RegisterClientScriptBlock(this, typeof(Page), "toggleBeforeUnload", "ToggleBeforeUnload(" + onOff.ToString().ToLower() + ");", true);
}
It calls the same JavaScript function described earlier. And sure enough, it works perfectly!
Incidentally, blessed is the Internet for helping out developers! I distinctly remember the days when there was no Internet. I'm absolutely convinced that it has dramatically improved the productivity and learning curve of developers around the world.
Labels:
AJAX,
ASP.net,
beforeunload,
draggable panel,
JavaScript
Monday, April 28, 2008
Warning the User About Prematurely Leaving a Web Page
I'm relatively new to website development. Up until now I've never had occasion to warn the user about leaving a web page. I knew it was possible though, as I'd seen it on some websites before.
I'm now working on a data editor that looks like this:
Essentially, the user can pick one of several bottom-level nodes in the treeview on the left and then the data associated with it will be displayed in the controls on the right. He might just view this data or may alter it. He can also add & delete & move nodes, each of which is connected with a data record.
A novice user wouldn't understand that all changes are handled locally and not updated in the database until 'Save' is pressed. So letting them enter a bunch of data and then close the browser or navigate to another page simply wasn't acceptable.
I found this article by well known ASP.Net guru, Scott Mitchell. It's actually the third in a trilogy of articles on the subject. I followed the basics of what he wrote and added this code to my ASPX page:
var needToConfirmExit = false; // Initialize
function ConfirmExit()
{
needToConfirmExit = Boolean(document.getElementById('<%= needToSaveData.ClientID %>').value);
if (needToConfirmExit)
return "You have made changes that have not yet been saved back to the database. If you leave now, all of those changes will be lost. Are you absolutely sure you want to do this?";
}
window.onbeforeunload = ConfirmExit;
The more advanced part of his article dealt with implementing an extensive client-side mechanism that kept track of which controls had their values changed. As my web page was AJAX enabled, partial page updates were occurring whenever any control's value was altered. So intuitively I knew there must be a simpler way
In the server-side code I already had a property called 'IsDirty' :
public bool IsDirty
{
get
{
return (bool)ViewState["IsDirty"]; // Note: If null then returns as false
}
set
{
ViewState["IsDirty"] = value;
ChangeButtonState(Constants.CommandButtons.Save, value);
needToSaveData.Value = value.ToString().ToLower();
}
}
'needToSaveData' is a hidden field that I placed inside the UpdatePanel. The beauty of this solution is that as soon as a control is updated, the 'ConfirmExit' JavaScript function is ready to go in case the user tries to prematurely leave the web page.
I'm now working on a data editor that looks like this:
Essentially, the user can pick one of several bottom-level nodes in the treeview on the left and then the data associated with it will be displayed in the controls on the right. He might just view this data or may alter it. He can also add & delete & move nodes, each of which is connected with a data record.A novice user wouldn't understand that all changes are handled locally and not updated in the database until 'Save' is pressed. So letting them enter a bunch of data and then close the browser or navigate to another page simply wasn't acceptable.
I found this article by well known ASP.Net guru, Scott Mitchell. It's actually the third in a trilogy of articles on the subject. I followed the basics of what he wrote and added this code to my ASPX page:
var needToConfirmExit = false; // Initialize
function ConfirmExit()
{
needToConfirmExit = Boolean(document.getElementById('<%= needToSaveData.ClientID %>').value);
if (needToConfirmExit)
return "You have made changes that have not yet been saved back to the database. If you leave now, all of those changes will be lost. Are you absolutely sure you want to do this?";
}
window.onbeforeunload = ConfirmExit;
The more advanced part of his article dealt with implementing an extensive client-side mechanism that kept track of which controls had their values changed. As my web page was AJAX enabled, partial page updates were occurring whenever any control's value was altered. So intuitively I knew there must be a simpler way
In the server-side code I already had a property called 'IsDirty' :
public bool IsDirty
{
get
{
return (bool)ViewState["IsDirty"]; // Note: If null then returns as false
}
set
{
ViewState["IsDirty"] = value;
ChangeButtonState(Constants.CommandButtons.Save, value);
needToSaveData.Value = value.ToString().ToLower();
}
}
'needToSaveData' is a hidden field that I placed inside the UpdatePanel. The beauty of this solution is that as soon as a control is updated, the 'ConfirmExit' JavaScript function is ready to go in case the user tries to prematurely leave the web page.
Sunday, April 27, 2008
Modal Popup Extender, StreamWriter
I've made a small, but useful enhancement to the Waikiki condo rental site I built. The owners of the condo have reservations well in advance so only need to find new people a few times a year. As such, they don't want people constantly writing them, saying such things as, "Hey, can I rent it next week?" This is a waste of time for the writer and for the condo owners.
One way to solve this would be for them to keep me updated about when it was available. But that would mean that I'd have to constantly update the site every few months. Sorry, not interested.
So I built a mechanism whereby they can customize a special message that appears when the user clicks on the Contact page. You can view the current message here:
What you're seeing is an effect provided by the ASP.Net AJAX Control Toolkit. It's called the Modal Popup Extender. It lets you display a Panel (ASP.Net's equivalent of a "Div") that contains whatever controls you want in it. In the example, there are only 3 objects:
.modalBackground
{
background-color:Gray;
filter:alpha(opacity=70); /* For IE */
opacity:0.7; /* For Firefox */
}
There's a new Admin page that I added, that is accessed via a link at the bottom of the page, followed by a required password. I could have implemented a full Login mechanism but thought it overkill for this simple application that will forever be used by only 2 people. With that said, I did not embed the password directly in the code for all code files get compiled into a DLL, which is normally accessible by a hacker via the ASP.net "bin" folder. So instead, I embedded the password in the very secure "web.config" file like this:
Arriving on the Admin page, one can only add/edit text and press "Submit" :
Implementing all of this was very simple. For example, the code that writes the text out to a file is this:
if (File.Exists(srcFile))
{
StreamReader streamReader;
string txt;
streamReader = File.OpenText(srcFile);
txt = streamReader.ReadToEnd();
streamReader.Close();
if (txt != "")
textBox1.Text = txt;
}
In my local test environment it worked perfectly. But intuitively I knew it wouldn't work right away on my GoDaddy hosted web server. Why? Three words: File write permissions
The text file in question resides in its own folder. This keeps it separate from the code and markup files. What I had to do was go into the GoDaddy File Manager, select this folder, and alter its Permissions so that Write was enabled and not just Read. Without doing that, the file is forever locked from any changes, short of FTP'ing in a new file.
Just some simple techniques here but together they allow for a nice and useful web application!
One way to solve this would be for them to keep me updated about when it was available. But that would mean that I'd have to constantly update the site every few months. Sorry, not interested.
So I built a mechanism whereby they can customize a special message that appears when the user clicks on the Contact page. You can view the current message here:
- The panel, which displays a background image
- A label, whose text is customized
- An "OK" button
.modalBackground
{
background-color:Gray;
filter:alpha(opacity=70); /* For IE */
opacity:0.7; /* For Firefox */
}
There's a new Admin page that I added, that is accessed via a link at the bottom of the page, followed by a required password. I could have implemented a full Login mechanism but thought it overkill for this simple application that will forever be used by only 2 people. With that said, I did not embed the password directly in the code for all code files get compiled into a DLL, which is normally accessible by a hacker via the ASP.net "bin" folder. So instead, I embedded the password in the very secure "web.config" file like this:
Arriving on the Admin page, one can only add/edit text and press "Submit" :if (File.Exists(srcFile))
{
StreamReader streamReader;
string txt;
streamReader = File.OpenText(srcFile);
txt = streamReader.ReadToEnd();
streamReader.Close();
if (txt != "")
textBox1.Text = txt;
}
In my local test environment it worked perfectly. But intuitively I knew it wouldn't work right away on my GoDaddy hosted web server. Why? Three words: File write permissions
The text file in question resides in its own folder. This keeps it separate from the code and markup files. What I had to do was go into the GoDaddy File Manager, select this folder, and alter its Permissions so that Write was enabled and not just Read. Without doing that, the file is forever locked from any changes, short of FTP'ing in a new file.
Just some simple techniques here but together they allow for a nice and useful web application!
Labels:
AJAX,
ASP.net,
GoDaddy,
modal popup,
security,
StreamWriter,
Web.config
Subscribe to:
Posts (Atom)