Está en la página 1de 13

7/12/22, 9:14 Combos en ASP.NET MVC – Burbujas en .

NET

Burbujas en .NET
Pues… cosas mías sobre .NET y desarrollo web.

Combos en ASP.NET MVC


Buenas! Una de las preguntas más referentes en ASP.NET MVC consiste en como crear combos, enlazarlas, etc, etc… La ver-
dad es que la documentación sobre este punto es un poco difusa y dispersa así que intentaré en este post mostrar un poco
las distintas formas que tenemos en ASP.NET MVC de crear combos.

Para ilustrar las distintas opciones partimos de una clase “Database” que simula un contexto de ORM. Es una clase que sim-
plemente tiene dos listas (estáticas), una de ciudades (Cities) y otra de provincias (States). La definición de las clases City y
State son:

    public class City


    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string CP { get; set; }
        public int StateId { get; set; }
    }
 
    public class State

https://geeks.ms/etomas/2013/04/25/combos-en-asp-net-mvc/ 1/13
7/12/22, 9:14 Combos en ASP.NET MVC – Burbujas en .NET

    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
1. SelectListItem

En HTML una combo (<select>) contiene una lista de opciones que siempre son clave y texto que se muestra (ambos alfanu-
méricos). Para representar esta información en ASP.NET MVC disponemos de la clase SelectListItem. SelectListItem nos per-
mite almacenar la clave (Value) y el texto (Text), así como un valor booleano (Selected) que indica si este es el elemento se-
leccionado por defecto a la combo (se corresponde al atributo selected del tag <option>).

Una posible forma de usarlo sería así:

var items = new List<SelectListItem>();


items = Database.Cities.Select(c => new SelectListItem()
    {
        Text = c.Name,
        Value = c.Id.ToString()
    }).ToList();
 
ViewBag.Cities = items;
return View();

Obtenemos las ciudades y luego convertimos cada objeto “City” en un objeto SelectListItem. Finalmente guardamos esta
lista de SelectListItem en el ViewBag.

Para mostrar esta combo basta con usar en la vista:

@Html.DropDownList("Cities")

El nombre usado “Cities” es el nombre del campo usado en el ViewBag y donde se encuentra la lista de SelectListItem.

https://geeks.ms/etomas/2013/04/25/combos-en-asp-net-mvc/ 2/13
7/12/22, 9:14 Combos en ASP.NET MVC – Burbujas en .NET

La combo generada tendrá un atributo name llamado Cities y esto es importante a la hora de recibir el valor seleccionado
de la combo. Hay una gran confusión en esto. Una combo envia UN SOLO ELEMENTO al controlador: El ID del elemento
seleccionado.

Veamos como podemos recibir la ciudad seleccionada:

[HttpPost]
public ActionResult Index(string Cities)
{
    var id = Int32.Parse(Cities);
    // Recuperamos la ciudad ==> Consulta a BBDD
    var city = Database.Cities.FirstOrDefault(c => c.Id == id);
    // Operamos con la ciudad
}

Dos cosas a destacar:

1. Lo que recibimos en Cities NO es la lista de ciudades. Es el valor de la propiedad Value del SelectListItem seleccionado
(en mi caso el ID de la ciudad seleccionada).
2. El nombre del parámetro (Cities) es el mismo que el nombre del campo del ViewBag (y el mismo que pusimos en la lla-
mada a Html.DropDownList).

2. IEnumerable

Tener que convertir siempre nuestros datos (en este caso una lista de ciudades) a una lista de SelectListItem es muy pesado.
Por suerte hay una clase SelectList que hace esto por nosotros. Basta con pasarle el IEnumerable que queremos, el nombre
de la propiedad que es la clave y el nombre de la propiedad que contiene el texto a mostrar.

public ActionResult Index()


{
    var items = Database.Cities;
https://geeks.ms/etomas/2013/04/25/combos-en-asp-net-mvc/ 3/13
7/12/22, 9:14 Combos en ASP.NET MVC – Burbujas en .NET

    ViewBag.Cities = new SelectList(items, "Id", "Name");


    return View();
}
En este punto ViewBag.Cities contiene una SelectList (que implemente IEnumerable<SelectListItem>) y el resto del código
ya es exactamente el mismo que antes.

3. Otros orígenes de datos

Hasta ahora en la vista hemos usado Html.DropDownList pasándole tan solo una cadena (Cities). Esta cadena determina:

El nombre del atributo name del <select> generado. Que a su vez es el nombre del parámetro cuando recibimos los datos
El nombre del campo del ViewBag que tiene los elementos.

Si no queremos que estos dos valores sean iguales, podemos espcificarle a Html.DropDown donde está el
IEnumerable<SelectListItem> que contiene los datos de la combo. Así en la vista podríamos utilizar:

@Html.DropDownList("selectedCity", ViewBag.Cities as IEnumerable<SelectListItem>)

Con esto le estamos diciendo que nos genere un <select> cuyo atributo name valga “selectedCity” y que los datos están en
ViewBag.Cities.

Ahora cuando recibimos los datos debemos tener presente que el parámetro ya NO se llama Cities, si no selectedCity:

[HttpPost]
public ActionResult Index(string selectedCity)
{
    var id = Int32.Parse(selectedCity);
    // Recuperamos la ciudad ==> Consulta a BBDD
    var city = Database.Cities.FirstOrDefault(c => c.Id == id);
    // Operamos con la ciudad
}

https://geeks.ms/etomas/2013/04/25/combos-en-asp-net-mvc/ 4/13
7/12/22, 9:14 Combos en ASP.NET MVC – Burbujas en .NET

4. HtmlDropDownListFor

Este helper lía un poco porque tendemos a compararlo con el resto de helpers similares. Así, si yo hago
Html.TextboxFor(m=>m.Name) me va a generar un Textbox vinculado a la propiedad Name del ViewModel de la vista.
HtmlDropDownListFor también espera una propiedad del modelo pero NO es la propiedad que tiene los elementos, si no
donde dejará el valor del elemento seleccionado.

Mucha gente se confunde y se cree que la propiedad que pasamos a Html.DropDownListFor es la propiedad que contiene
los valores a mostrar. Imaginemos que tenemos el siguiente ViewModel:

public class ComboCitiesViewModel


{
    public IEnumerable<City> Cities { get; set; }
    public int SelectedCity { get; set; }
}

La acción Index nos queda ahora de la siguiente forma:

public ActionResult Index()


{
    var items = Database.Cities;
    var vm = new ComboCitiesViewModel();
    vm.Cities = items;
    return View(vm);
}

Para usar Html.DropDownListFor podemos hacerlo tal y como sigue:

@Html.DropDownListFor(m=>m.SelectedCity, new SelectList(Model.Cities, "Id", "Name"))

Le paso DOS parámetros a Html.DropDownListFor:

https://geeks.ms/etomas/2013/04/25/combos-en-asp-net-mvc/ 5/13
7/12/22, 9:14 Combos en ASP.NET MVC – Burbujas en .NET

1. La propiedad del ViewModel que contendrá el valor seleccionado


2. El IEnumerable<SelectListItem> con los datos. Fijaos que en este caso dado que mi ViewModel contiene un
IEnumerable<City> uso la clase SelectList que hemos visto antes para hacer la conversión.

Para recibir los datos puedo declarar la siguiente acción:

[HttpPost]
public ActionResult Index(ComboCitiesViewModel info)
{
    var id = info.SelectedCity;
    // Recuperamos la ciudad ==> Consulta a BBDD
    var city = Database.Cities.FirstOrDefault(c => c.Id == id);
    // Operamos con la ciudad
}

Y aquí es donde hay otro punto de confusión: en info NO VAS A RECIBIR la lista de ciudades. Es decir la propiedad Cities va
a ser null:

¿Y eso? Pues bueno, simple y llanamente nadie manda estos valores de vuelta para el controlador. La lista de ciudades NO
está en la petición POST que hace el navegador y por lo tanto el controlador no la recibe.

De hecho, podríamos modificar el parámetro ComboCitiesViewModel para que fuese un string llamado SelectedCity y fun-
cionaría igual.

5. Combos encadenadas

https://geeks.ms/etomas/2013/04/25/combos-en-asp-net-mvc/ 6/13
7/12/22, 9:14 Combos en ASP.NET MVC – Burbujas en .NET

Lo que vamos a ver es una implementación de combos encadenadas pero SIN ajax. Es decir, seleccionas provincia, envías la
petición y te aparecen las ciudades. En una web “actual” seguramente se haría via Ajax, pero hacerlo de la “manera anti-
gua” nos permitirá terminar de ver como funcionan las combos.

Antes que nada modificamos el viewmodel:

public class ComboCitiesViewModel


{
    public IEnumerable<City> Cities { get; set; }
    public int SelectedCity { get; set; }
    public IEnumerable<State> States { get; set; }
    public int SelectedState { get; set; }
}

La acción Index que envía la página inicial la modificamos para que rellene States:

public ActionResult Index()


{
    var items = Database.States;
    var vm = new ComboCitiesViewModel();
    vm.States = items;
    return View(vm);
}

La vista nos quedará de la siguiente forma:

@model MvcCombos.Models.ComboCitiesViewModel
 
@using (Html.BeginForm()) {
    <label for="Cities">Ciudad:</label>
 
        @Html.DropDownListFor(m=>m.SelectedState, new SelectList(Model.States, "Id", "Name"))

https://geeks.ms/etomas/2013/04/25/combos-en-asp-net-mvc/ 7/13
7/12/22, 9:14 Combos en ASP.NET MVC – Burbujas en .NET

 
    if (Model.SelectedState != 0)
    {
        @Html.DropDownListFor(m=>m.SelectedCity, new SelectList(Model.Cities, "Id", "Name"))
    }
 
    <input type="submit" value="enviar" />
}
Es importante entender lo que hacemos en la vista:

1. Si NO hay provincia seleccionada (Model.SelectedState vale 0) entonces mostramos la primera combo para seleccionar
estado.
2. Si hay estado seleccionado entonces generamos la combo para seleccionar la ciudad.

Nota: Este código tiene algunos problemas, como p.ej. que ocurre si el usuario selecciona una provincia,
envía el formulario, y cuando aparece de nuevo la vista con las dos combos modifica la provincia
seleccionada? En una aplicación real deberías, al menos, deshabilitar la combo de estados cuando ya
haya estado seleccionado.

Y finalmente ahora la acción que recibe los resultados debe gestionar que será llamada dos veces (una para seleccionar el
estado, la segunda con estado y ciudad):

[HttpPost]
public ActionResult Index(ComboCitiesViewModel info)
{
    if (info.SelectedState != 0 && info.SelectedCity == 0)
    {
        info.States = Database.States;
        info.Cities = Database.Cities.Where(c => c.StateId == info.SelectedState);
        return View(info);

https://geeks.ms/etomas/2013/04/25/combos-en-asp-net-mvc/ 8/13
7/12/22, 9:14 Combos en ASP.NET MVC – Burbujas en .NET

    }
 
    var id = info.SelectedCity;
    // Recuperamos la ciudad ==> Consulta a BBDD
    var city = Database.Cities.FirstOrDefault(c => c.Id == id);
    // Operamos con la ciudad
}
Fíjate en un par de cosas:

1. Debemos volver a cargar todos las provincias dentro del viewmodel. Si no cuando la vista intente renderizar la combo de
provincias dará error.
2. En las ciudades seleccionamos tan solo aquellas que son de la provincia que el usuario ha seleccionado.

Insisto, en una vista “real” la segunda vez no mostraríamos la combo de provincias, quizá mostraríamos el nombre de la
ciudad seleccionada. Veamos como podríamos hacerlo.

Por un lado podemos modificar el viewmodel:

public class ComboCitiesViewModel


{
    public IEnumerable<City> Cities { get; set; }
    public int SelectedCity { get; set; }
    public IEnumerable<State> States { get; set; }
    public int SelectedState { get; set; }
    public string SelectedStateName { get; set; }
}

Añadimos la propiedad para guardar el nombre de la provincia seleccionada. Y en la vista usamos esta propiedad o
Html.DropDownList en función de si hay o no provincia seleccionada:

@model MvcCombos.Models.ComboCitiesViewModel

https://geeks.ms/etomas/2013/04/25/combos-en-asp-net-mvc/ 9/13
7/12/22, 9:14 Combos en ASP.NET MVC – Burbujas en .NET

 
@using (Html.BeginForm()) {
    <label for="Cities">Ciudad:</label>
 
    if (Model.SelectedState == 0)
    {
        @Html.DropDownListFor(m => m.SelectedState, new SelectList(Model.States, "Id", "Name"))
    }
    else
    {
        <text>Provincia @Model.SelectedStateName </text>
        @Html.DropDownListFor(m=>m.SelectedCity, new SelectList(Model.Cities, "Id", "Name"))
    }
 
    <input type="submit" value="enviar" />
}
Finalmente en la acción que recibe los datos nos ahorramos de rellenar de nuevo las provincias (ya que la vista ya no las
usará la segunda vez) y ponemos el nombre de la provincia seleccionada (fíjate que hemos de ir a buscarlo a la BBDD ya
que solo tenemos el ID):

[HttpPost]
public ActionResult Index(ComboCitiesViewModel info)
{
    if (info.SelectedState != 0 && info.SelectedCity == 0)
    {
        info.SelectedStateName = Database.States.Single(s => s.Id == info.SelectedState).Name;
        info.Cities = Database.Cities.Where(c => c.StateId == info.SelectedState);
        return View(info);
    }
 
    var id = info.SelectedCity;
    // Recuperamos la ciudad ==> Consulta a BBDD
    var city = Database.Cities.FirstOrDefault(c => c.Id == id);
https://geeks.ms/etomas/2013/04/25/combos-en-asp-net-mvc/ 10/13
7/12/22, 9:14 Combos en ASP.NET MVC – Burbujas en .NET

    // Operamos con la ciudad


}
Con esta aproximación:

1. La primera vez la vista mostrará la combo de provincias y el controlador recibirá en SelectedState el id de la provincia
seleccionada.
2. La segunda vez la vista mostrará un texto con el nombre de la provincia y la combo de ciudades y el controlador recibirá
en SelectedCity el ID de la ciudad seleccionada. Esta segunda vez el controlador NO recibirá SelectedState ya que no se
envía. En nuestro caso no es necesario ya que lo podemos sacar de la ciudad. Si fuese necesario deberíamos usar un
campo Hidden.

Bueno… creo que esto más o menos es todo. ¡Espero que este post os ayude a resolver las dudas que podáis tener con las
combos en ASP.NET MVC!

¡Un saludo!

 25 abril, 2013  etomas  Sin categoría

4 comentarios sobre “Combos en ASP.NET MVC”

kiquenet
26 abril, 2013 a las 08:00

Fabuloso Eduard ! Saludos.

https://geeks.ms/etomas/2013/04/25/combos-en-asp-net-mvc/ 11/13
7/12/22, 9:14 Combos en ASP.NET MVC – Burbujas en .NET

sebastianherrera
2 mayo, 2013 a las 17:52

Eduard, este caso muestra el ejemplo de dos tablas, una para estado y otra para city.

que cambiara en el caso de que sea un combo multiple para una sola tabla?. ejemplo tipico es la tabla categorias con multi-
ples parent id.
ejemplo:
categoryid | nombre de categoria | parent_categoryid

existe forma de hacer un multiples combos en funcion de la cantidad de parent categories que tenga?

muchas gracias!
sebastian.

etomas 
8 mayo, 2013 a las 16:45

Buenas @sebastianherrera

ASP.NET MVC no soporta directamente el concepto de «combo múltiple para una sola tabla». Es decir, tu debes leer los datos
de esa tabla y organizarla en dos combos: dos objectos SelectList que mandas hacia la vista.

Saludos!

anonymous
12 noviembre, 2013 a las 14:54
https://geeks.ms/etomas/2013/04/25/combos-en-asp-net-mvc/ 12/13
7/12/22, 9:14 Combos en ASP.NET MVC – Burbujas en .NET

Buenas! Este post es para describir un fallo que he encontrado en el helper Html.DropDownFor y el workaround

Creado con WordPress

https://geeks.ms/etomas/2013/04/25/combos-en-asp-net-mvc/ 13/13

También podría gustarte