Pages

Advertisement

Friday, July 13, 2007

Dynamically Linked Comboboxes Set

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.

About the Author
I am a programmer for database application and data aware web sites.

Downloads

  • DynLinkedCombo_demo.zip -
  • DynLinkedCombo_src.zip - contain two Source code cs files needed for develop custom control server sisde code.
  • DynLinkedCombo_tools.zip - contain files that is necessary to implement this custom control in ASP .NET project
  • No comments:

    Post a Comment