DropDownList en cascada con Javascript y ASP.NET
Para iniciar con esta entrada es necesario tener instalado en nuestro servidor de SQL la base de datos Northwind la cual se puede descargar aquí ya que se utilizaran las tablas Region y Territories de dicha base de datos para llenar dos dropdownlist que van en cascada.
Crearemos un proyecto de ASP.NET vacío y agregaremos una página con el nombre Default.aspx y en nuestra página agregaremos 2 dropdownlist y 2 labels como se muestra a continuación:
<asp:Label ID="lblRegion" runat="server" Text="Region:"></asp:Label> <asp:DropDownList ID="ddlRegion" runat="server" Width="145px"> </asp:DropDownList> <br /> <asp:Label ID="lblTerritory" runat="server" Text="Territory:"></asp:Label> <asp:DropDownList ID="ddlTerritory" Width="145px" runat="server"> </asp:DropDownList>
Agregaremos a nuestro archivo Web.config la cadena de conexión a nuestro servidor de SQL donde se encuentra montada la base de datos Northwind y le asignaremos el nombre de NorthwindConnectionString como se muestra a continuación:
<connectionStrings> <add name="NorthwindConnectionString" connectionString="Data Source=.;Initial Catalog=Northwind;User ID=sa2" providerName="System.Data.SqlClient" /> </connectionStrings>
En el codebehind de nuestra página agregaremos un método con el nombre de BindRegionCombo() el cual hará el trabajo de llenar nuestro combo de regiones realizando una consulta a la tabla Region de nuestra base de datos Northwind, nuestra rutina se vera de la siguiente manera:
protected void BindRegionCombo() { SqlConnection sqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString.ToString()); SqlCommand sqlCom = new SqlCommand("SELECT RegionID, RegionDescription FROM Region", sqlCon); SqlDataReader sqlDr = null; try { sqlCon.Open(); sqlDr = sqlCom.ExecuteReader(); this.ddlRegion.Items.Clear(); while (sqlDr.Read()) { this.ddlRegion.Items.Add(new ListItem(Convert.ToString(sqlDr[1]).Trim(), Convert.ToString(sqlDr[0]).Trim())); } this.ddlRegion.Items.Add(new ListItem("--", String.Empty)); this.ddlRegion.SelectedIndex = this.ddlRegion.Items.Count - 1; } catch (Exception ex) { Response.Write(ex.Message.ToString()); } finally { sqlCon.Close(); sqlDr.Dispose(); } }
Haremos la llamada de nuestra rutina en el evento Page_Load de nuestra página Default.aspx como se muestra a continuación:
protected void Page_Load(object sender, EventArgs e) { BindRegionCombo(); }
En el codebehind de nuestra página agregaremos una función con el nombre de GetTerritoryData() la cual realizara una consulta a la tabla Territories y retornara todos los registros de esta. Se construirá en una variable de tipo cadena los elementos de un arreglo de javascript y ejecutaremos dicha funcion en el cabecero de nuestra página Default.aspx la cual escribirá en cliente los elementos de nuestro arreglo nuestra función luciría de la siguiente manera:
protected string GetTerritoryData() { string strTerritories = String.Empty; SqlConnection sqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString.ToString()); SqlCommand sqlCom = new SqlCommand("SELECT RegionID, TerritoryID, TerritoryDescription FROM Territories ORDER BY RegionID, TerritoryDescription", sqlCon); SqlDataReader sqlDr = null; try { sqlCon.Open(); sqlDr = sqlCom.ExecuteReader(); Int32 i = 0; while (sqlDr.Read()) { strTerritories += "territories[" + i + "] = new Array(" + Convert.ToString(sqlDr[0]).Trim() + ", '" + Convert.ToString(sqlDr[1]).Trim() + "', '" + Convert.ToString(sqlDr[2]).Trim() + "');\n"; i += 1; } } catch (Exception ex) { Response.Write(ex.Message.ToString()); } finally { sqlCon.Close(); sqlDr.Dispose(); } return strTerritories; }
Ejecutaremos la función anterior con las etiquetas en el cabecero dentro de nuestra pagina después de declarar un arreglo javascript con el nombre de territories.
var territories = new Array(); <%= GetTerritoryData() %>
Crearemos una función javascript dentro de nuestra pagina Default.aspx con el nombre de bindTerritoryCombo la cual recibirá como parámetro el objeto RegionID con el identificador de la región seleccionada la cual dependerá para el llenado del combo de territorios
En esta función primeramente obtendremos nuestro control dropdownlist de territorios accesando a el con la función getElementById
var ddlTerritory = document.getElementById("ddlTerritory");
Obtendremos su longitud y realizaremos un for para eliminar cada uno de las opciones del dropdownlist, esto se realizara cada vez que se seleccione una nueva opción en el control de las regiones para eliminar las opciones previas del dropdownlist
var lengthddlTerritory = ddlTerritory.length - 1; for(var i = lengthddlTerritory; i >= 0; i--){ ddlTerritory.options[i] = null; }
Realizaremos otro ciclo para recorrer nuestro arreglo de territorios el cual se alimentó desde una consulta que se ejecutó del lado del servidor y con una condicionante de acuerdo al parámetro recibido en nuestra función iremos asignando uno por uno las nuevas opciones de nuestro dropdownlist
var j = 0; for(var i = 0; i < territories.length; i++){ if(territories[i][0] == RegionID){ ddlTerritory.options[j] = new Option(territories[i][2], territories[i][1]); j++; } }
Al final simplemente agregaremos otra opción vacía y la seleccionaremos para mostrar una opción default
ddlTerritory.options[j] = new Option("--", ""); ddlTerritory.selectedIndex = j;
La función que acabamos de crear se llamara en el evento OnChange de nuestro dropdownlist de Regiones, así cada vez que seleccionemos una nueva opción nuestra función se ejecutara y llenara nuestro dropdownlist de territorios sin la necesidad de volver a ejecutar la consulta en la base de datos ni de de refrescar la pagina cada vez que seleccionemos una nueva opción.
<asp:DropDownList ID="ddlRegion" runat="server" Width="145px" OnChange="bindTerritoryCombo(this.value)"> </asp:DropDownList>
Nuestra pagina Default.aspx se vería de la siguiente manera:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Populate_Dropdownlist.Default" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> <script type="text/javascript"> var territories = new Array(); <%= GetTerritoryData() %> function bindTerritoryCombo(RegionID){ var ddlTerritory = document.getElementById("ddlTerritory"); var lengthddlTerritory = ddlTerritory.length - 1; for(var i = lengthddlTerritory; i >= 0; i--){ ddlTerritory.options[i] = null; } var j = 0; for(var i = 0; i < territories.length; i++){ if(territories[i][0] == RegionID){ ddlTerritory.options[j] = new Option(territories[i][2], territories[i][1]); j++; } } ddlTerritory.options[j] = new Option("--", ""); ddlTerritory.selectedIndex = j; } </script> </head> <body> <form id="form1" runat="server"> <div> <asp:Label ID="lblRegion" runat="server" Text="Region:"></asp:Label> <asp:DropDownList ID="ddlRegion" runat="server" Width="145px" OnChange="bindTerritoryCombo(this.value)"> </asp:DropDownList> <br /> <asp:Label ID="lblTerritory" runat="server" Text="Territory:"></asp:Label> <asp:DropDownList ID="ddlTerritory" Width="145px" runat="server"> </asp:DropDownList> </div> </form> </body> </html>
Nuestro codebehind Default.aspx.cs se vería de la siguiente manera:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Data.SqlClient; using System.Configuration; namespace Populate_Dropdownlist { public partial class Default : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { BindRegionCombo(); } protected void BindRegionCombo() { SqlConnection sqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString.ToString()); SqlCommand sqlCom = new SqlCommand("SELECT RegionID, RegionDescription FROM Region", sqlCon); SqlDataReader sqlDr = null; try { sqlCon.Open(); sqlDr = sqlCom.ExecuteReader(); this.ddlRegion.Items.Clear(); while (sqlDr.Read()) { this.ddlRegion.Items.Add(new ListItem(Convert.ToString(sqlDr[1]).Trim(), Convert.ToString(sqlDr[0]).Trim())); } this.ddlRegion.Items.Add(new ListItem("--", String.Empty)); this.ddlRegion.SelectedIndex = this.ddlRegion.Items.Count - 1; } catch (Exception ex) { Response.Write(ex.Message.ToString()); } finally { sqlCon.Close(); sqlDr.Dispose(); } } protected string GetTerritoryData() { string strTerritories = String.Empty; SqlConnection sqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString.ToString()); SqlCommand sqlCom = new SqlCommand("SELECT RegionID, TerritoryID, TerritoryDescription FROM Territories ORDER BY RegionID, TerritoryDescription", sqlCon); SqlDataReader sqlDr = null; try { sqlCon.Open(); sqlDr = sqlCom.ExecuteReader(); Int32 i = 0; while (sqlDr.Read()) { strTerritories += "territories[" + i + "] = new Array(" + Convert.ToString(sqlDr[0]).Trim() + ", '" + Convert.ToString(sqlDr[1]).Trim() + "', '" + Convert.ToString(sqlDr[2]).Trim() + "');\n"; i += 1; } } catch (Exception ex) { Response.Write(ex.Message.ToString()); } finally { sqlCon.Close(); sqlDr.Dispose(); } return strTerritories; } } }
Al terminar nuestra pagina se vera de la siguiente manera:
a mi lo que me pasa es que ta entiendo como anda y lo hago andar me anda lo que pasa si uso esos ddllist para guardarlos en un tabla no me guarda el ddlterritory que podra ser
Gabriel
26 marzo, 2012 at 12:29 PM
si quiero guardar el resultado de la seleccion que elijo en el ddlist pierdo el estado del control es decir si tengo este codigo
param[6] = new SqlParameter(«@Ciudad», SqlDbType.VarChar);
param[6].Value = ddlTerritory.SelectedValue.ToString();
param[6].Direction = ParameterDirection.Input;
param[7] = new SqlParameter(«@Pais», SqlDbType.VarChar);
param[7].Value = ddlRegion.SelectedItem.Value;
param[7].Direction = ParameterDirection.Input;
no me guarda ningun valor pierde el estado del conttrol
alguna idea para que no se pierda el estado
Gabriel
27 marzo, 2012 at 5:31 AM