jueves, enero 12, 2012

Carga de combos en cascada en página web mediante Ajax y Json

Untitled Page

cuestión a resolver

Imaginemos que queremos cargar 3 combos en cascada, que contienen respectivamente continentes, países y ciudades: Cuando el usuario cambie el valor del primer combo (continente) hay que cambiar el contenido del combo de países, y cuando cambie el de países, hay que cambiar el de las ciudades.

Esta otra entrada de mi blog hace referencia a algunos de los conceptos que aquí se utilizan: Actualización de datos en página web mediante AJAX y JSON

 

parte cliente

Definición de los combos EN Html

 

<select name="cmbContinentes" id="continentes" class="combosLugar"></select>
<select name="cmbPaises" id="paises" class="combosLugar "></select>
<select name="cmbCiudades" id="ciudades" class="combosLugar"></select>

        

eL CÓDIGO Javascript

1.       En la carga de la pantalla (con jQuery) añadir la carga del primer combo que a su vez desencadena la carga de los siguientes, y el evento .change para los elementos con class="comboDeLugar" (es decir, nuestros combos).

$(document).ready(function () {

 

    // Cargar 1er combo (que a su vez desencadena la carga de los demás)
    cargaCombo("cmbContinentes"'../../Lugar/Continentes'null);
 
    // Definición evento OnChange para los combos de medida de neumáticos
    $(".combosLugar").change(function (e) {
        cargaSiguienteCombo(this.id)
    });
 
    // Inicialización (opcional). Sólo el primer combo a modo de ejemplo.
    $("#comboContinentes")[0].value = "cmbContinentes"
  

}

 

2.       Definición de la función que carga un combo mediante Ajax y Json

    // Cargar combo de forma asíncrona, utilizando ajax y formato json.
    function cargaCombo(cmb, url, params) {
        $.ajax({
            url: url,
            data: params,
            dataType: 'json',
            success: (function (data) {
                $("#" + cmb).html('');
                $.each(data, function (i, item) {
                    $("#" + cmb).append("<option value='" +
                        item.Value + "'>" + item.Text + "</option>");
                });
                cargaSiguienteCombo(cmb);
            })
        });
    }

 

3.       Definición de la función que carga el siguiente combo.

    // Cargar el siguiente combo
    function cargaSiguienteCombo(changedCombo) {
 
        if (changedCombo == "") {
            return cargaCombo(
                "cmbContinentes",
                '../../Lugar/Continentes',
                null
            );
        }
 
        if (changedCombo == "cmbContinentes") {
            return cargaCombo(
                "cmbPaises",
                '../../Lugar/Paises',
                "continente=" + $("#cmbContinentes")[0].value
            );
        }
 
        if (changedCombo == "cmbPaises") {
            return cargaCombo(
                "cmbCiudades",
                '../../Lugar/Ciudades', 
                "pais=" + $("#comboPaises")[0].value
            );
        }
    }

 

parte servidor: la clase que recibe las peticiones ajax

Partimos de la base de que utilizamos ASP.Net MVC 3.

La definición de las entidades Continente, Pais y Ciudad no se describe en este documento, porque son muy simples. Sólo indicaré que están ligadas a sendas tablas cuyos campos son:

·         Continentes: Nombre

·         Paises: Nombre, Continente

·         Ciudades: Nombre, Pais

La definición de la clase que recibe las peticiones Ajax desde el código javascript de la página web, es la siguiente:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Dream.Models;
 
namespace MiProyecto.Controllers
{
    public class LugarController : Controller
    {
        private MisEntities db = new MisEntities();
         
        /// <summary>
        /// Retorna los continentes, hardcoded (no desde BDD)
        /// </summary>
        /// <returns></returns>
        public JsonResult Continentes()
        {
 
            var list = new List<object>() {
                new { Text = "Europa", Value = "Europa" },
                new { Text = "América", Value = "América" },
                new { Text = "Asia", Value = "Asia" },
                new { Text = "África", Value = "África" },
                new { Text = "Oceanía", Value = "Oceanía" },
            };
 
            return this.Json(list, JsonRequestBehavior.AllowGet);
        }
 
        /// <summary>
        /// Retorna los países de cierto continente
        /// </summary>
        /// <param name="continente">Nombre de continente</param>
        /// <returns></returns>
        public JsonResult Paises(string continente)
        {
            var list = from pais in db.Paises
                where pais.Continente == continente
                select new { Text = pais.Nombre, Value = pais.Nombre };
 
            return this.Json(list.ToList(), JsonRequestBehavior.AllowGet);
        }
 
        /// <summary>
        /// Retorna las ciudades de cierto pais
        /// </summary>
        /// <param name="pais">Nombre de pais</param>
        /// <returns></returns>
        public JsonResult Ciudades(string pais)
        {
            var list = from ciudad in db.Ciudades
                where ciudad.Pais == pais
                select new { Text = ciudad.Nombre, Value = ciudad.Nombre };
 
            return this.Json(list.ToList(), JsonRequestBehavior.AllowGet);
        }
    }