Dynamically Linked Comboboxes Set

Introduction

If you frequently create comboboxes range-bounded with a database and have tired to write the same code, this article for you. During enter or searching process on a Web site, you often need to use a selected element in the first combobox to fill up the second comboboxfrom the database, a selected element in the second combo to fill up the third combo, and so forth. At the same time, you might need to a page refresh without a submit as well.

Realization

I attempted to solve this problem by realizing a Custom control idea implemented in ASP .NET and well explained in Jeff Prosize’s book Programming Microsoft .NET. To realize refreshing w/o submit, I organized my .aspx file in a frameset with one hidden frame; this one pumps all data from the database and fills up comboboxes in visible frame without submitting it. This realization must job on all browsers that support carrying over an OPTION object of the SELECT tag between frames (in particular, IE 5.5 and higher).

Source Code

The control’s server source is in LocControl.cs, the hidden frame’s code-behind in HiddenFrm.aspx.cs. In both, two functions for filling up comboboxes by a SQL or OLE DB data provider have been realized. To activate the SQL data provider, it is necessary to add the SqlServer=”true” attribute in kar tag; otherwise, the control will use the OLE DB provider and the developer must apply the appropriate Connection string. The client-side code is in scripts.js.

Let us describe the outline of the program’s job.

  1. The custom control begins its job from the source provided in Loccontrol.cs and rendering the needed HTML code to the container aspx file at the time of its loading and filling up the first combobox.
  2. The user-select item in the filled combo client code (OnChange() from scripts.js) carries out needed data to fill the next combo in HiddenFrm.aspx and submits it.
  3. The server code in HiddenFrm.aspx.cs fills in the next combo.
  4. The client code in HiddenFrmOnLoad() fills up the combo in the container page where comboboxes are set. The user continues to select the program carried out in Step 2.

Fragments of LocControl.cs

   public class LocControl: System.Web.UI.Control
   {
      ...
      ...

public string SqlServer    // if this attribute value = true then
                           // custom will use SQL Data Provider;
                           // otherwise, OLE DB Provider
      {
         get{ return bSqlServer;}
         set{ bSqlServer= value;}
      }
      public string ComboData
      // String separated by ";" for each combobox.Between ";" write
      // data needed for fill OPTION  elements of SELECT tag
      // separated by space ' '.
      //
      // For First element: will be three parameters
      // First parameter: Table name from assigned in ConString
      // data source
      // Second paramente: Field name of Table that will be text
      // value of combobox
      // Third parameter: Field name of Table that wi be the value
      // for combobox item and will use for seek in following
      // combobox
      // For Follwing comboboxes will be four parameters:
      // First three parameters have same meaning that was for
      // First combobox.
      // Fourth parameter point out the key field in the Table where
      // you select data for this combobox.

      {
         get { return CDates;}
         set {CDates = value;}
      }
      public string ConString    // set connection string for
                                 // the appropriate provider
      {
         get{ return scon;}
         set{ scon = value;}
      }
      public string Captions     //comboboxes captions
      {
         get{ return  sCaptions;}
         set{ sCaptions = value;}
      }
   protected override void Render(HtmlTextWriter writer)
   // fill custom control HTML code on page
   //
      {
         string htextname = "";
         //check ComboData attribute for empty
         if(CDates == null)
            return;

         ArrayComboDates = CDates.Split(';');  // separate ComboData
                                               // attribute's data
         int comboquantity = ArrayComboDates.Length;

// hidden textbox to save ComboData attribute of control
         writer.WriteBeginTag("input");

         ...

// hidden textbox to save connection string
         writer.WriteBeginTag("input");
         writer.WriteAttribute("type","hidden");
         string hconnection = UniqueID+"_sconn";
         writer.WriteAttribute("name",hconnection);
         if(bSqlServer == "true")
            writer.WriteAttribute("value", scon
               + "??" + "true");
         else
            writer.WriteAttribute("value",scon );
         writer.Write(HtmlTextWriter.TagRightChar);

         // begin <table tag to arrange control's elements
         writer.WriteBeginTag("table");
            ...

         // print captions for each combobox
         writer.WriteFullBeginTag("tr");
         writer.WriteLine();
         if(sCaptions !=null)
          capsarray  = sCaptions.Split(';');
            ...

         // print SELECT tags for each combobox
         writer.WriteFullBeginTag("tr");

         string[]  ctrlname = new string[comboquantity];
         for(int i=0; i < comboquantity; i++)
         {
            //begin td
            writer.WriteBeginTag("td");
            writer.WriteAttribute("align","center");
            writer.Write(HtmlTextWriter.TagRightChar);
            writer.WriteLine();
            writer.WriteBeginTag("select");

            ctrlname[i] = string.Format("{0}_{1}",this.UniqueID,i+1);

            writer.WriteAttribute("name", ctrlname[i]);
            if(i != (comboquantity - 1))
            writer.Write("OnChange="OnChange(this.options
                         [this.selectedIndex].value,
                         this.name,this.form.name," +
                         comboquantity.ToString() + "," + htextname
                         + "," + hconnection + ")"");
            if(ID!=null)
               writer.WriteAttribute("id",this.ClientID);
            writer.Write(HtmlTextWriter.TagRightChar);
            // fill up first combobox
            if(i == 0)
               if(bSqlServer == "true")
                  FillClCombo(i,writer);      // fill up by SQL
                                              // provider
               else
                  FillClCombo_uni(i,writer);  // fill up by OLE DB
                                              // provider
            writer.Write("</select>");
            writer.WriteEndTag("td");
            writer.WriteLine();

         }
         writer.WriteEndTag("tr");
         writer.Write("</Table>");

      }

When the user selects an item in the combo, appropriate data are transferred from your .aspx file to hidden frame(HiddenFrm.aspx) by the OnChange() function from the subscript.js file.

JavaScript Source Code

void function OnChange(combovalue,name,frmname,comboquantity,htext,
                       hconnection)
{
   // get general base of combobox names using active combobox name
   var baseofname = name.substr(0,name.lastIndexOf("_") + 1);
   var number = name.substr(name.lastIndexOf("_")+1,name.length);
   var intnumber = parseInt(number) + 1;
   var nextcomboname;
//clean up subsequent comboboxes
   for( i=intnumber; i < comboquantity; i++)
   {
      var n = i+1;
      nextcomboname = baseofname + n
      eval("document." + frmname + "." + nextcomboname +
           ".length = 0;");
   }
   //passing data from active page to Hidden form(HiddenFrm.aspx)
   eval("var cfrm = document." + frmname);
   eval("parent.bottomFrame.document.HiddenFrm.combotext.value=" +
        combovalue);
   parent.bottomFrame.document.HiddenFrm.comboname.value=frmname +
          "." + name;
   parent.bottomFrame.document.HiddenFrm.TextCDatas.value =
          htext.value;
   parent.bottomFrame.document.HiddenFrm.TextConnection.value =
          hconnection.value;
   parent.bottomFrame.document.HiddenFrm.submit();
}

Come back to the server side and look at HiddenFrm.aspx.cs. The job continues here.

Fragments from HiddenFrm.aspx.cs

namespace HiddenFrm_ns
{
   public class HiddenFrm : System.Web.UI.Page
   {
      ...
      ...

      private void Page_Load(object sender, System.EventArgs e)
      {
         string apppath =Context.Request.ApplicationPath;
         //register script block
         string scrsrc = "<script src=" + apppath +
                          "/KarControl/script.js></script>";
         if(!IsClientScriptBlockRegistered("cSrcript"))
            RegisterClientScriptBlock("cScript", scrsrc);
            Response.Write("<br>");
         // Get filled from active page data and fill up the
         // intermediate combo
         NameValueCollection fnv = Request.Form;
         if(fnv.Count !=0)
         {
            string[] condata = (Request.Form.GetValues(
                                "TextConnection")[0]).Split('?');
            con = condata[0];
            string combotext = fnv.GetValues("combotext")[0];
               //key value for filter data from next table in
               //database
            string comboname = (fnv.GetValues("comboname"))[0];
               //name of combo that initiate submit in active page
               //get name of next combo
            char[] d = {'_'};
            int ind = comboname.LastIndexOfAny(d);
            string cnum = comboname.Substring(ind+1,
                          comboname.Length -(ind + 1));
            int  icombonum =(int)Convert.ChangeType(cnum,
                                                    ind.GetType());
            icombonum = icombonum + 1;
            string ctrlname = comboname.Substring(0,ind+1);
            string nextcombo = ctrlname + icombonum.ToString();
            // if after connection string is ; and "true" word this
            // is SqlServer mode
            if(condata.Length == 3 && condata[1] == "" &&
                                      condata[2]=="true")
               FillComboSql(combotext,icombonum);    // fill combo
                                                     // by SQL
                                                     // Provider
            else
               FillComboUni(combotext,icombonum);    // fill combo
                                                     // by OLE DB
                                                     // provider

            this.comboname.Text  = nextcombo;
         }

      }
      ...
      ...
   }
}

The back stream of data to your active page provides the HiddenFrmOnLoad() function from the subscript.js file.

JavaScript Source Code from scropt.js

//send filled up combobox.s data from HiddenFrm.aspx to your
//active page
void function HiddenFrmOnLoad()
{
   var op;
   var text;
   if(document.HiddenFrm.comboname.value != "")
   {
      text = "var mcombo = parent.mainFrame.document." +
             HiddenFrm.comboname.value;
      eval(text);
      mcombo.options[0]= new Option("","");
      for(i=0; i < document.HiddenFrm.hcombo.length; i++)
      {

         op = document.HiddenFrm.hcombo.options[i];
         mcombo.options[i+1] = new Option(op.text,op.value);
      }
      mcombo.length = document.HiddenFrm.hcombo.length + 1;
   }
}

Using the Source

You don’t need save the LocControl.cs and HiddenFrm.aspx.cs files in your project; their compiled code is in LocControl.dll. If you want to change this source, apply this command line:

csc /t:library /out:LocControl.dll LocControl.cs HiddenFrm.aspx.cs.

The manual for applying for this custom control is in Readme.txt in the KarControl folder.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read