ASP.NET MVC: Autocompletado con enums

La verdad es que el tema de los enums y ASP.NET MVC da para hablar bastante (yo mismo hice un post hace ni mucho). Pero hace algunos días mi buen amigo y a veces rival, Marc Rubiño publicó en su blog un interesante artículo sobre como crear combos que mostrasen valores de enums.

En este post voy a mostrar una técnica parecida, pero a través de las data list, un concepto nuevo de HTML5 que como pasa muchas veces está recibiendo menos atención de la que merece. Y es que las data list nos dan una manera fácil y sencilla de tener cajas de texto que se autocompleten.

Qué son las data lists de HTML5?

Bueno, pues como ya debes deducir de su nombre las data list no es nada más que la posibilidad de definir un concepto nuevo, que es esto: una lista de datos.

Una lista de datos se usa como fuente de datos para un control que pueda tener una y lo bueno es que el viejo y a veces injustamente denostado <input type=”text”> entran en esta categoría. Honestamente no entiendo como el <select> no tiene soporte para data lists. Quiero suponer que hay alguna explicación, pero la verdad no la encuentro. Bueno, da igual… ¡al tajo!

La definición de una data list es muy simple:

<datalist id="sexo">

    <option value="N">Nada</option>

    <option value="P">Poco</option>

    <option value="M">Mucho</option>

    <option value="D">Demasiado</option>

</datalist>

Ahora en HTML5 podemos usar el atributo list de la etiqueta <input> para asociar a un <input> (p. ej. una caja de texto) una lista de valores:

<input type="text" id="txtSexo" list="sexo" placeholder="Sexo" autocomplete="on" />

Básicamente tan solo se trata de usar el atributo list con el valor del id de la data list a usar.

El atributo id es requerido por Chrome (si no se aplica al <input> Chrome ignora el atributo list). Este es el resultado en Chrome, Opera e IE10:

image

Podemos ver las diferencias entre navegadores:

  • Chrome nos muestra el value a la izquierda y la descripción a la derecha
  • Opera tan solo nos muestra el value
  • IE10 tan solo nos muestra la descripción

Sin duda el mejor mecanismo, en mi opinión, es el de Chrome, luego el de Opera y por último el de IE10. No he podido probar FF ni Safari por no tenerlos a mano en el momento de escribir el post.

Igual te sorprende que prefiera que el desplegable muestre N, P, M y D como hace Opera en lugar de Nada, Poco,… que muestra IE10. Eso es porque el valor que se debe teclear en el textbox es el de value. El valor de value es el que se almacena en el textbox, y por lo tanto es el que debe teclearse (a diferencia de la <select> que permite mostrar un valor y mandar otro el <input type=”file” /> no tiene esta opción).

Ten presente siempre que estamos usando un <input type=”text” /> por lo que el usuario puede entrar lo que quiera. No es como una <select> donde debe elegir un elemento de los que le indiquemos. Así pues los elementos de la data list son ¡más una sugerencia que una obligación!

Un ejemplo.

Veamos como podríamos usar esto con enums y MVC…

Lo primero es definirnos un enum:

    public enum Beers

    {

        Estrella_Damm,

        Voll_Damm,

        Moritz,

        Epidor,

        Mahou,

        Cruzcampo

    }

Ahora vamos a extender la clase HtmlHelper con un método de extensión nuevo que llamaremos TextBoxEnumerableFor:

    public static class HtmlHelperEnumExtensions

    {

        public static IHtmlString TextBoxEnumerableFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Type enumerationType, Expression<Func<TModel, TProperty>> expression)

        {

            var httpContext = helper.ViewContext.HttpContext;

            var html = new StringBuilder();

            if (httpContext.Items[enumerationType.FullName] == null)

            {

 

                httpContext.Items.Add(enumerationType.FullName, GenerateDataList(enumerationType, html));

            }

            var textbox = helper.TextBoxFor(expression, new {list = enumerationType.FullName});

            html.AppendLine(textbox.ToString());

            return MvcHtmlString.Create(html.ToString());

        }

 

        private static string GenerateDataList(Type enumerationType, StringBuilder html)

        {

            var id = enumerationType.FullName;

            html.AppendFormat(@"<datalist id=""{0}"">", id);

            html.AppendLine();

            foreach (var item in Enum.GetNames(enumerationType))

            {

                html.AppendFormat(@"<option>{0}</option>", item.Replace(‘_’, ‘ ‘));

                html.AppendLine();

            }

            html.AppendLine("</datalist>");

 

            return id;

        }

    }

Aspectos a comentar de este código:

  1. Uso HttpContext.Items para “hacer un seguimiento” de si ya se ha creado una datalist. Esto es para no definir en el mismo HTML dos veces la misma datalist si se generan dos (o más) cajas de texto vinculadas al mismo enum.
  2. Sustituyo los guiones bajos (_) por un espacio. Eso debería tenerse en cuenta luego al recibir los datos.

Este código es muy sencillo y realmente debería sobrecargarse el método para dar más opciones (p. ej. especificar atributos html adicionales que ahora no es posible). Pero como ejemplo, creo que sirve.

Su uso es muy sencillo:

@using MvcApplication1

@using MvcApplication1.Models

@model MvcApplication1.Models.BeerModel

 

@{

    ViewBag.Title = "Index";

}

Entra el nombre de tu cerveza preferida aquí:

 

@Html.TextBoxEnumerableFor(typeof(Beers), m=>m.BeerName)

BeerName es una propiedad (string) del modelo BeerModel. Y este es el HTML generado:

Entra el nombre de tu cerveza preferida aquí:

<datalist id="MvcApplication1.Models.Beers">
<option>Estrella Damm</option>
<option>Voll Damm</option>
<option>Moritz</option>
<option>Epidor</option>
<option>Mahou</option>
<option>Cruzcampo</option>
</datalist>
<input id="BeerName" 
    list="MvcApplication1.Models.Beers" 
    name="BeerName" 
    type="text" value="" />

No generamos atributo value, en este caso dicho atributo toma el valor del propio texto del option.

Y un pantallazo de como se ve en Opera:

image

Puedes ver como se usa los elementos del enum para mostrar una sugerencia de autocompletado del textbox. Pero recuerda: el usuario puede entrar el valor que quiera.

Como digo, el código se puede mejorar mucho, pero como idea y ejemplo creo que es suficiente.

Un saludo!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *