Hi Everyone !

I have 2 DropDownList controls inside an UpdatePanel.

The first is a dropdown for Country while the second is for State.

I have set the properties of Country as AutoPostBack="True", OnSelectedIndexChanged ="PopulateState". Selecting a different Country fires the PopulateState function causing the the State to populate itself with the relevant states as well as state id (StateID and StateName are selected from the State table. The Country dropdown contains the CountryID and CountryName selected from the Country table).

Outside the UpdatePanel, there is a Button control, say "Submit Form". This runs a sql Select statement, picking up the CountryID value from the Country DropDownList, as well as the StateID from the State DropDownList.

On my development server, the State dropdown is populated very fast. Hence, when I click on Button Control, I get the expected results.

However, on the production server when a different Country is selected, it takes about 5+ seconds for the (partial page update) State dropdown to have the relevant StateID and StateName.

I tried setting the Button's Enable property to false at the start of the PopulateState function and then to true at the end of the function. This does not work.

Please tell me...
1. How to disable the Button contol when the Country is changed and then enable it again when the States have been populated(ie for the 5+ seconds it takes for the partial page update)?

Thanks.

Recommended Answers

All 10 Replies

I think you are going to have to use client side javascript to disable the button.
In the head of your page put this javascript

<script type="text/javascript">
    function disable()
    {
      document.getElementById("Button1").disabled = "true";
    }
</script>

and for your dropdownlist control use this

<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="true" 
        OnSelectedIndexChanged="PopulateState" onChange="disable();">
</asp:DropDownList>

Now I am not sure how this is going to work with a partial page update but its all I can think of.

Thanks Freon22

When you say "onChange", I'm assuming you mean "OnTextChanged". Is my assumption correct?

Whilst doing some research, I found that the last post on the link http://forums.asp.net/p/1447282/3296130.aspx states that "Based on my test, the TextChanged and SelectedIndexChanged behaves similar.. the only thing i noticed is that the SelectedIndexChanged fires first before TextChanged event"

It appears that OnSelectedIndexChanged will run before OnTextChanged, still giving the opportunity for me to click on the (Enabled) Button.

What could possibly be a solution/workaround to this issue?

When you say "onChange", I'm assuming you mean "OnTextChanged". Is my assumption correct?

Whilst doing some research, I found that the last post on the link http://forums.asp.net/p/1447282/3296130.aspx

The OnTextChanged is for firing a method on a text change within a textbox. The OnSelectedIndexChanged is for firing a method on a dropdownlist. You can not have a text change in a dropdownlist because you can not change the text. The most you can do is change the selected index.

Getting back to your problem what I think you said was that you needed to disable a button control while you did a postback. So the best way to do this is on the client side, so you need to call a javascript function that can disable the button. So when the selected index in the dropdownlist changes the "OnSelectedIndexChanged" fires the asp method and the "onChange" fires the client side javascript funtion that disables the button control.

I tested it and it works good the only thing I am not sure of is you said you are doing a partial postback so I am assuming you are using ajax? I did not test it in a ajax update panal.

Hi Freon22
Thanks for the reply.

You were right about OnTextChanged being non existent.

Here is a snippet of my code

Contents of the C# code behind

protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            ddlCountry.Attributes["onchange"] = "javascript:ddCountryPostback();";
	.
        .
        . 
       }
   }

Contents of the aspx page, including javascript.

function ddCountryPostback() {
            var btnSearch = document.getElementById('<%=btnSearch.ClientID %>');
            btnSearch.disabled = true;
            //Mainframe is the Master page			
            __doPostBack('ctl00$cph_Mainframe_Header$ddCountry', '');
            btnSearch.disabled = false;
         }

function validateSave() {
            var ddlCountry= document.getElementById('<%=ddlCountry.ClientID%>');
            var ddlState = document.getElementById('<%=ddlState.ClientID%>');
            
            if (ddlCountry.selectedIndex == 0) {
                alert('Please select Country');
                ddlCountry.focus();
                return false;
            }

            if (ddlState .selectedIndex == 0) {
                  alert('Please select state');
                   ddlState .focus();
                   return false;
            }
}



<asp:UpdatePanel ID="upnl" runat="server" 
       ChildrenAsTriggers="False" UpdateMode="Conditional">
<ContentTemplate>
          <asp:Literal runat="server" ID="ltrl_Country" Text="some text"></asp:Literal>: 
<asp:DropDownList ID="ddlCountry" runat="server" AutoPostBack="false"   OnSelectedIndexChanged="ddlCountry_SelectedIndexChanged">
</asp:DropDownList>
            

<asp:Literal runat="server" ID="ltrlStateName" Text="State"></asp:Literal>:  <asp:DropDownList ID="ddlState" Enabled="false" runat="server" >
</asp:DropDownList>
</ContentTemplate>
                                
       <Triggers>
          <asp:AsyncPostBackTrigger ControlID="ddlCountry" />
       </Triggers>
</asp:UpdatePanel>

The "Select" item is first on the dropdown of both Country and State.
I do a javascript validation (validateSave) when I click the btnSearch.

In an effort to disable the btnSearch, I have made the UpdateMode="conditional".
Changing the Country dropdown fires the ddCountryPostback function.

I select both the dropdowns and hit btnSearch. It works fine
Now I change Country; and without waiting for the state to populate with new values I click btnSearch.
In the 5+ seconds it takes to populate State, if btnSearch is clicked, the validateSave is ineffective.
(I'm just thinking...perhaps when validation occurs it is ok. ie value has not yet been fetched, but the old state value is still there.)

How to I tackle this issue?
Thanks to one and all...

Question, when you select a Country does the bthSearch become disabled? If it does then for how long, does it become enabled before the States dropdownlist populates?

Another question when you do the postback is the javascript reloaded? The reason being that if the javascript is reloaded with the partial postback then it not going to work. I see your <asp:UpdatePanel if that the only part being postback then the javascript should be good.

What you may need to do is to keep the btnSearch disabled for 5 seconds so your states dropdownlist has a chance to finish populating.

What happens with the code below is when the dropdownlist selected index changes then your ddCountryPostback is fired. It disables the btnSearch button then calls the _doPostBack, it then set a timeout for 5 seconds and at the end of that 5 seconds it call the enable function that enable the button again so it can be clicked on.

function ddCountryPostback() {
var btnSearch = document.getElementById('<%=btnSearch.ClientID %>');
   btnSearch.disabled = true;
   //Mainframe is the Master page
   __doPostBack('ctl00$cph_Mainframe_Header$ddCountry', '');
   
   //Set a time out of 5 seconds before the button is enabled.
   setTimeout('enable()', 5000); 
}

function enable() {
   document.getElementById('<%=btnSearch.ClientID %>').disabled = false;
}

Hi Freon22
Thanks once again.

To answer your question the btnSearch remains enabled at all times. I conclude that it disables and enables it without waiting for

__doPostBack('ctl00$cph_Mainframe_Header$ddCountry', '');

to finish.

It's worth mentioning that the btnSearch is an ImageButton. Like so

<asp:ImageButton ID="btnSearch" runat="server"  OnClick="loadData" 
OnClientClick="return validateSave();" />

Yes, your code does cause a delay of 5000 milliseconds (5 secs). My case scenario is such that the time taken could be more than 5 seconds. A way to simulate that was to put the following statement in the ddlCountry_SelectedIndexChanged function (C# page)

//Simulate a long running operation
    System.Threading.Thread.Sleep(30000);

After researching the net, I was trying the example demonstrated in the link
(Disable Button On Submit (Prevent Multiple Submits))
http://www.devtoolshed.com/content/disable-button-submit-prevent-multiple-submits

But apparently since the btnSearch doesn't cause a page_load, keeping the button disabled after clicking.

The next example I'm going to implement will be the one indicated in

http://www.codeproject.com/Articles/96407/How-to-disable-subsequent-submit-button-clicks-whe.aspx
But here the button is inside the UpdatePanel.

(PS. I have kept backups of the pages, so that if you or any one else has any ideas they can be tried out.)
Let's see how this one goes...

Thanks once again

I like helping others because while doing so I learn also. Anyway I think I have solved your problem. What we have been doing is to try and disable the btnSearch, LOL I was all wrong. I code an app just like your for testing and played try to make it work. I had to take a step back and it came to me. :)

What we should be doing is asking the ScriptManager if it is done with the partial postback. This can be done in your validateSave function, use the code below.

function validateSave() {
        var ddlCountry= document.getElementById('ddlCountry');
        var ddlState = document.getElementById('ddlState');
        var myTest = Sys.WebForms.PageRequestManager.getInstance();
        
        if (myTest.get_isInAsyncPostBack()) {
            alert('Still loading States');
            return false;
        }
        
        if (ddlCountry.selectedIndex == 0) {
            alert('Please select Country');
            ddlCountry.focus();
            return false;
        }
        
        if (ddlState.selectedIndex == 0) {
            alert('Please select state');
            ddlState.focus();
            return false;
        }      
      }

Hi Freon22

Yes, you are right. That does it. Mission accomplished. :)

Although the btnSearch could not be disabled, the main objective of making sure that the
code runs only after proper validation has been achieved.
Disabling the btnSearch might not be achievable since this button resides outside the UpdatePanel. Partial page postbacks affect only those controls inside an UpdatePanel.

Moments before I read your reply I just did it by putting a HiddenField(HFLoadCompleteFlag) in the UpdatePanel.

(aspx page)

function ddCountryPostback() {
     var btnSearch = document.getElementById('<%=btnSearch.ClientID %>');
     [B]HFLoadCompleteFlag.value = '1';[/B]//loading in progress
        //Mainframe is the Master page
     __doPostBack('ctl00$cph_Mainframe_Header$ddCountry', '');
}
function validateSave() {
        var ddlCountry= document.getElementById('ddlCountry');
        var ddlState = document.getElementById('ddlState');
        var HFLoadCompleteFlag = document.getElementById('<%=HFLoadCompleteFlag.ClientID%>');

        if (HFLoadCompleteFlag.value == '1') {
                return false;
            }
.
.
.
}

(C# page)
In the function ddlCountry_SelectedIndexChanged

HFLoadCompleteFlag.Value = "0";

is the last statement.

On a side note the article titled "Why ASP.NET AJAX UpdatePanels are dangerous" http://encosia.com/2007/07/11/why-aspnet-ajax-updatepanels-are-dangerous/ makes an interesting read.

Thanks for the trouble

Yes I had thought of using the modalpopupextender also. The only reason I did not pursue that method was that it adds more html and css to the page and you may have some cross browser compatibility issues. I do use the modalpopupextender on one of my login pages. But its more to just add the cool effects of having my page gray out and the login info displayed to the front.

But he is right if you use the modalpopupextender then nothing else can clicked on the page until the modalpopupextender is removed. So using that method will work or you can just ask the ScriptManager if it is done with the partial postback.

Anyway this has been a fun problem to help you with. I learned while doing it and we both have come out with better code.

Take Care and Happy Coding!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.