Blog de Jonathan Ojeda

Mi diario de programación

DropDownList en cascada con Javascript y ASP.NET

with 10 comments

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>
        &nbsp;&nbsp;
        <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>
        &nbsp;&nbsp;
        <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:

Written by jcrappy

11 febrero, 2011 a 2:14 PM

Publicado en Otros, Programación

Tagged with , , , , ,

10 respuestas

Subscribe to comments with RSS.

  1. 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

  2. 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


Deja un comentario