9

i have a web-page with two <asp:DropDown> controls:

enter image description here

When the user selects a Country i want to fill the list of states.


Attempt #1 - OnSelectedIndexChanged

The first thing was pretty simple: during OnSelectedIndexChanged of the first drop-down, fill the second box:

//be sure to set AutoPostBack of cbCountry to true in the properties window

protected void cbCountry_SelectedIndexChanged(object sender, EventArgs e)
{
   cbState.Items.Clear();
   FetchStatesForCountryIntoStateDropDown(cbState, cbCountry.SelectedValue);
   if (cbState.Items.Count > 0)
      cbState.SelectedIndex = 0;
}    

That worked well enough, except that it triggers a page refresh. The user is interrupted while the post is sent, and the page is reloaded. And the page is no longer where they left it, and they are no longer sitting inside the drop-down.


Attempt #2 - Old fashioned kludgey UpdatePanels

@Seglo calls UpdatePanels an old-fashioned kludge. But since i can't find anything better - let's try it! Wrap the stuff in an update-panel, and let it do it's magic:

enter image description here

The problem with that is that when the UpdatePanel updates, it deletes both controls and replaces them with new ones. This means that the user has lost their focus in the first dropdown. People have suggested horrible kludges using javascript to try to save and restore the focus. But i'd rather do things correctly.


Attempt #3 - Only UpdatePanel what you need to Update

i don't need to update the Country dropdown (nor the labels). i only need to update the State dropdown; so why not wrap only that in an <asp:UpdatePanel>. In fact this is the answer suggested on StackOverflow:

enter image description here

And that works. The Country dropdown doesn't lose focus. The OnSelectedIndexChanged event fires, and the State dropdown fills...

...the first time i change the country dropdown.

If i change the Country again, it throws an exception:

Invalid postback or callback argument.

Somehow the updatepanel is messing with the WebForms controls; making the postback data invalid. This makes sense, since messing with WebForms controls makes the postback data invalid.


Attempt #4 - Try faking a postback myself using javascript

It doesn't gain you anything; but people have tried triggering a postback manually through javascript:

$('#userControl1').on('focusout', function() {
     __doPostback('UpdatePanel2UniqueId', '');
});

Except without knowing the ClientID of cbCountry and UpdatePanel1, the script won't run; nor do i even know if it can solve my problem


Attempt #5 - Use PageMethods to fetch the State list.

Now i'm only linking other people's random suggestions. It takes me about 4 hours to try to implement any suggestion. Which means i've lost a day and a half trying to fill a combo-box.

i can't afford to lose a day on every random suggestion i find on google; i need an actual answer. So i'm only including them to show the grumpy people that there was research effort (as though research effort was important).

Some people have suggested calling ASP.net PageMethods, and update the cbState in client javascript:

function GetStates(country)
{
    PageMethods.GetTeam(teamCode, CountryCallback);
}

function CountryCallback(result)
{
    var teamName = $get('TeamName');
    var seed = $get('Seed');
    var rpi = $get('RPI');
    var scoutingReport = $get('ScoutingReport');
    teamName.innerText = result.TeamName;
    seed.innerText = result.Seed;
    rpi.innerText = result.RPI;
    scoutingReport.innerText = result.ScoutingReport;
}

onchange="GetTeam(this.options[this.selectedIndex].value);"

Problem here is the same at Attempt#2. The viewstate will be wrong because i've mucked with the form behind ASP.net's back.


There seems to be a fundamantal problem that ASP.net and viewstate are fundamentally incompatible with client-side DOM updates. Any attempt to modify a page client-side invalidates the entire ASP.net web-forms programming model.

Community
  • 1
  • 1
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • 1
    You've nailed it, the ViewState is almost universally going to prevent you from doing a lot of this. It's why we went from a ViewState based model to a nearly pure MVC model. I suggest using PageMethods TWICE, once to do your updates, and AGAIN to SUBMIT the form. Then redirect when the second PageMethod is successful. (that will happen really quickly, you'll be surprised) === the alternative is to use UpdatePanel and suffer the wait. === to be fair, there are ways of making what you're asking for work, but they take a LOT longer than a second PageMethod when you're not familiar already. – jcolebrand Jun 28 '12 at 20:37
  • Agreed. After fighting with UpdatePanel and implementing awkward workarounds, I finally got away from them completely and use WebMethods/jQuery to do magic. – Dimitri Jun 28 '12 at 20:41
  • @Dimitri Doesn't modifying the page client-side cause the `Invalid postback or callback argument.` error when you do that? – Ian Boyd Dec 14 '12 at 22:08
  • You could use a page method to create a drop down list. Render it to a string and insert the html output into the page using jquery. – George Filippakos Mar 15 '13 at 22:44

5 Answers5

1

Use the AJAX Control Toolkit... it has a CascadingDropDown which would be perfect! :)

http://www.asp.net/ajaxLibrary/AjaxControlToolkitSampleSite/CascadingDropDown/CascadingDropDown.aspx

Nerdwood
  • 3,947
  • 1
  • 21
  • 20
0

Updating the DropDownList controls using javascript won't alter the viewstate, which means that in each post the changes will be overridden.

I have done something similar serializing to JSON the content of the lists in hidden fields and then in server code deserializing it on each post

This is an answer that shows a full working example to show something similar (check the accepted answer).

ASP.NET jQuery double listbox edit and save

Edit 1

BTW In order to get rid of:

Invalid postback or callback argument.

You can disable the viewstate validation, however this is not recommended, you should only do it if you are in an intranet where you can trust most of the time in your users

<%@ Page EnableEventValidation="false"
Community
  • 1
  • 1
Jupaol
  • 21,107
  • 8
  • 68
  • 100
0

I have a trick and it works. It is using a hidden button inside the same update pane the the State dropdown.

<script type="text/javascript">
    function ddlCountry_changed() {
        document.getElementById('<%= btnLoad.ClientID %>').click();
    }
</script>

Country:
<asp:DropDownList ID="ddlCountry" runat="server" onchange="ddlCountry_changed();">
    <asp:ListItem Text="Vietnam" Value="1"></asp:ListItem>
    <asp:ListItem Text="United State" Value="2"></asp:ListItem>
</asp:DropDownList>

<asp:UpdatePanel ID="updatePanel" runat="server">
    <ContentTemplate>
        <asp:Button ID="btnLoad" style="display: none" runat="server" OnClick="btnLoad_OnClick" />
        State:
        <asp:DropDownList ID="ddlState" runat="server">
        </asp:DropDownList>
    </ContentTemplate>
</asp:UpdatePanel>

Code behind:

    protected void btnLoad_OnClick(object sender, EventArgs e)
    {
        ddlState.Items.Clear();

        if (ddlCountry.SelectedValue == "2")
        {
            ddlState.Items.Add(new ListItem() { Text = "California", Value = "1" });
        }
        else
        {
            ddlState.Items.Add(new ListItem() { Text = "Saigon", Value = "2" });
        }
    }
phnkha
  • 7,782
  • 2
  • 24
  • 31
0

Related to Attempt#1 to solve the problem of the page position you can try using this in the aspx page header

<%@ Page MaintainScrollPositionOnPostback="true" %>

and register a javascript in the cbCountry_SelectedIndexChanged method to set focus at the state combobox.

Rob
  • 4,927
  • 12
  • 49
  • 54
-2

Go to the setting of the dropdownList

Set AutoPostBack=True ,