Remember Cascading Dropdown value when navigating away from page

Viewed 301

I maintain an application for my organization that uses Web Forms. I have to add cascading dropdowns and I need to have those dropdowns remember their values when I navigate away from the page. My first dropdown remembers its value but its cascading dropdown does not retain its value when I navigate back. Any suggestions?

Below are my dropdowns:

 <asp:UpdatePanel ID="updatePanel1" runat="server">
    <ContentTemplate><div class="dropDownSelection">
      <asp:DropDownList CssClass="topicDropDown" ID="topic1" DataTextField="NAME" DataValueField="ID" OnSelectedIndexChanged="Load_Section1" AutoPostBack="True" AppendDataBoundItems="true" runat="server"/>
      <asp:DropDownList CssClass="sectionDropDown" ID="section1" DataTextField="NAME" DataValueFile="ID" AutoPostBack="True" runat="server">
        <asp:ListItem Text="--- Select Section ---" Value="0"></asp:ListItem>
         </asp:DropDownList></div><br/>
    </ContentTemplate>
 </asp:UpdatePanel>

Below are the methods that load the dropdown values:

protected void Load_Topic1()
    {
        var topicStore = new TopicStore();

        var topics = topicStore.ReadTopics();

        foreach (var topic in topics)
        {
            var topicListItem = new ListItem(topic.Name, topic.Id.ToString());
            topic1.Items.Add(topicListItem);
            //topic1.Attributes.Add("Title", topic.Description);//only shows description for item at the bottom of the dropdown
        }

        topic1.Items.Insert(0, new ListItem("--- Select Topic ---", "0"));
    }

    protected void Load_Section1(object sender, EventArgs e)
    {
        section1.Items.Clear();

        var sectionStore = new SectionStore();

        var sections = sectionStore.ReadForTopic(Guid.Parse(topic1.SelectedValue));

        foreach (var section in sections)
        {
            var sectionListItem = new ListItem(section.Name, section.Id.ToString());
            section1.Items.Add(sectionListItem);
        }

        section1.Items.Insert(0, new ListItem("--- Select Section ---", "0"));
    }

Load_Topic1 is called on page load. The values of the dropdowns are stored in session when you navigate away from the page.

Below is how I load the values into session:

if (Session["Page"] != null)
{
    if (Session["SubmittedPayment"] != null)
    {
        //shazbot -- they've already hit submit
        Server.Transfer("default.aspx?logout=true");
    }
   topic1.SelectedValue = Session["topic1"] as string;
  section1.SelectedValue = Session["section1"] as string;
  rating1DropDown.SelectedValue = Session["rating1DropDown"] as string; 

    if (Session["Page"].ToString() == "HighSchoolInformation2.aspx")
    {
        Session.Add("Page", "InterestSurvey.aspx");
    }
    else if (Session["Page"].ToString() == "Payment.aspx" || Session["Page"].ToString() == "InterestSurvey.aspx")
    {
        Session.Add("Page", "InterestSurvey.aspx");
    }
  else 
  {
      topic1.SelectedValue = Session["topic1"] as string;
      section1.SelectedValue = Session["section1"] as string;
      rating1DropDown.SelectedValue = Session["rating1DropDown"] as string;
      Response.Redirect(Session["Page"].ToString());
   } 
}
   else
    {
    //they're not logged in, send them back to log in
    Server.Transfer("Default.aspx?logout=true");
    } 

In the code behind I load session variables like this:

protected void next_Click(object sender, EventArgs e)
    {
        Session.Add("topic1", topic1.SelectedValue);
        Session.Add("section1", section1.SelectedValue);
        Session.Add("rating1DropDown", rating1DropDown.SelectedValue);

        Page.Validate();
        if (Page.IsValid)
        {
            ModLangRequired.Visible = false;

            if (!checkModLang())
            {
                Response.Redirect("Payment.aspx");
            }
        }
    }

Like I said up top I inherited this code and I don't have the time for a complete rewrite at the moment.

2 Answers

Start by changing Load_Section1 as follows. Notice how we are using Guid.TryParse to conditionally load sections if a topic is selected.

protected void Load_Section1()
{
    section1.Items.Clear();

    section1.Items.Add(new ListItem("--- Select Section ---", "0"));

    Guid topicId;
    if (Guid.TryParse(topic1.SelectedValue, out topicId))
    {
        var sectionStore = new SectionStore();

        var sections = sectionStore.ReadForTopic(topicId);

        foreach (var section in sections)
        {
            var sectionListItem = new ListItem(section.Name, section.Id.ToString());
            section1.Items.Add(sectionListItem);
        }
    }
}

Then add a new event handler as follows:

protected void TopicDropDown_OnSelectedIndexChanged(object sender, EventArgs e)
{
    Load_Section1();
}

Now associate the OnSelectedIndexChanged event to the new handler:

<asp:DropDownList ID="topic1" ... OnSelectedIndexChanged="TopicDropDown_OnSelectedIndexChanged" ... />

Now you can restore the the page state as follows:

if (Session["Page"] != null)
{
    if (Session["SubmittedPayment"] != null)
    {
        //shazbot -- they've already hit submit
        Server.Transfer("default.aspx?logout=true");
    }

    Load_Topic1();
    topic1.SelectedValue = IsPostBack ? Request.Form[topic1.UniqueID] : (string)Session["topic1"];
    Load_Section1();
    section1.SelectedValue = IsPostBack ? Request.Form[section1.UniqueID] : (string)Session["section1"];
    Load_Rating1DropDown(); // not sure if you need this???
    rating1DropDown.SelectedValue = IsPostBack ? Request.Form[rating1DropDown.UniqueID] : (string)Session["rating1DropDown"];   

    if (Session["Page"].ToString() == "HighSchoolInformation2.aspx")
    {
        Session.Add("Page", "InterestSurvey.aspx");
    }
    else if (Session["Page"].ToString() == "Payment.aspx" || Session["Page"].ToString() == "InterestSurvey.aspx")
    {
        Session.Add("Page", "InterestSurvey.aspx");
    }
    else 
    {
        // you don't actually need to set values before you redirect
        Response.Redirect(Session["Page"].ToString());
    } 
}
else
{
    //they're not logged in, send them back to log in
    Server.Transfer("Default.aspx?logout=true");
}

My assumption is the above code is called from Page_Load. Avoid making any extra calls to Load_Topic1 as well.

Actually what's happening is, your cascade dropdown (section1) load it's items on the selection of topic1, and when page refresh, topic1 fetch it's value from managed ViewState and section1 renders blank...

There are 2 solutions:

Manage it in script

Store section1's selectedValue in any storage like ViewState or localStorage (browser storage) and on document ready, you can fetch items for section1 against item selected in topic1 through ajax call and set the selected value which is stored in storage. (Sounds much efforts, check below option)

Manage it in back-end code

In your Page_Load method, call Load_Section1 and pass topic1.SelectedValue

Don't forget to put Page.IsPostBack condition to avoid error...

Related