Cómo obtener el valor de campos de formulario con el mismo nombre

Imaginemos el siguiente código HTML:

<input type="text" name="nombre" /><br />

<input type="text" name="nombre" /><br />

Si desde un servidor ASP.NET, como respuesta a un submit (o postback en webforms), queremos acceder a los valores del campo del formulario “nombre”, podemos utilizar el clásico Request[“nombre”] para obtener los valores de todos ellos separados por comas.

Así, si introducimos en el primer campo el valor “Juan” y en el segundo “Pedro”, Request["nombre"] contendrá “Juan,Pedro”. Esto podría ser suficiente para procesarlo troceando la cadena a partir de las comas, por ejemplo así:

string[] nombres = Request["nombre"].Split(',');

 

string n1 = nombres[0]; // n1 = "Juan"

string n2 = nombres[1]; // n2 = "Pedro"

Sin embargo, es obvio que esta técnica genera problemas si un usuario introduce en alguno de los campos una coma, el carácter que estamos considerando como separador de los elementos.

La forma correcta de hacerlo sería utilizando el método GetValues() sobre la propiedad Form de la petición, la cual nos devuelve un array con los valores de cada campo. Por ejemplo, si en el primer campo introducimos “Juan,Jose” y en el segundo “Luis”, el resultado sería el que sigue:

string[] nombres = Request.Form.GetValues("nombre");

string n1 = nombres[0]; // Juan,Jose

string n2 = nombres[1]; // Luis

 

En ASP.NET MVC, el sistema de bindings es capaz de facilitarnos aún más las cosas. Si en la vista existen diferentes campos llamados “nombre”, y el submit se realiza sobre una acción en cuyos parámetros aparece un array con la misma denominación, recibiremos los datos directamente:

[AcceptVerbs(HttpVerbs.Post)]

public ActionResult Editar(string[] nombre)

{

    // nombre[0] -> "Juan,Jose"

    // nombre[1] -> "Luis"

}

Crossposteando desde: Cómo obtener el valor de campos de formulario con el mismo nombre | Variable not found 

12 buenas prácticas en ASP.NET MVC

 

imageSimone Chiaretta, desarrollador, MVP, bloguero y autor de un libro sobre ASP.NET MVC Framework, entre otros méritos, recoge en su recomendable bitácora Code Climber unas cuantas buenas prácticas a considerar cuando trabajamos en proyectos ASP.NET MVC, que cito y comento a continuación:

  1. Borra el AccountController. Siendo fieles al principio YAGNI, prácticamente lo primero que deberíamos hacer al crear un proyecto ASP.NET MVC es eliminar todo lo relativo al sistema de cuentas de usuario incluido por defecto en el mismo, que muy difícilmente nos será útil tal cual en proyectos reales.

     

  2. Aísla los controladores del mundo exterior, no dejes que dependan de elementos externos como HttpContext,  datos del reloj (hora/fecha actual), ni accedas directamente a bases de datos o elementos de configuración. Harán tu aplicación muy poco flexible y difícil de testear.

     

  3. Utiliza un contenedor IoC, te ayudará a gestionar las dependencias de los controladores, facilitando la sustitución de estos elementos de forma muy sencilla, sobre todo, vistas a la realización de pruebas.

     

  4. No utilices cadenas mágicas, dificultan la detección de errores. No es buena idea usar expresiones del tipo ViewData["variable"], las vistas tipadas son el mecanismo ideal para pasar información desde el controlador. También es peligroso el uso de los helpers que utilizan cadenas para referirse a nombres de controladores y acciones, y para ello existen alternativas basadas en expresiones lambda o plantillas T4 bastante potentes.

     

  5. Crea tus propias convenciones tomando como base las propuestas por el framework MVC. Por ejemplo, crea controladores y vistas base de las que heredar, e implementa en ellos aspectos comunes.

     

  6. Presta atención a los Verbos, a los verbos HTTP, claro ;-). Envía información desde formularios con el método POST y genera las vistas que muestran datos desde peticiones GET. Utiliza el patrón Post-Redirect-Get.

     

  7. DomainModel != ViewModel, el primero representa los datos y lógica del dominio, mientras que el segundo se diseña exclusivamente para satisfacer las necesidades de información de las vistas y normalmente serán estructuras planas, y principalmente strings, que es el tipo de datos que normalmente necesitan los controles de entrada y salida de datos.

     

  8. Usa ActionFilters para manejar los datos compartidos entre distintas acciones y controladores, dejando que éstos se centren en la tarea que deben realizar. Puedes utilizar filtros para cargar información común (por ejemplo, para componentes de una página maestra) y utilizar vistas parciales para mostrarla.

     

  9. No utilices el code-behind. Nunca. En mi opinión, el code-behind no es necesario (al menos no le he encontrado aún ninguna utilidad en MVC), y puede crear confusión si compartes tu código con otros desarrolladores que no esperarán encontrar nada ahí.

     

  10. Escribe HTML siempre que puedas. No utilices helpers que lo único que van a hacer es generar el código HTML por ti. Es decir, mejor usar <input type="submit" value="grabar" /> que <%=Html.Submit("grabar") %>.

     

  11. Si hay un if, escribe un helper. Las vistas deben ser fáciles de leer, y muchos bloques de códigos mezclados con marcado no facilita la tarea. Dado que en las vistas la lógica ha de ser necesariamente muy simple, probablemente puedas crear helpers que simplifiquen la composición del marcado en casos en los que hay condiciones if o bucles for .

     

  12. Elige el motor de vistas cuidadosamente, WebFormViewEngine no es el único ni, para Simone, el mejor de los existentes. De hecho, recomienda el uso de Spark, un motor de vistas libre en el que es el propio HTML el que controla el flujo de composición del interfaz de forma muy sencilla y potente:

     

  13. <viewdata products="IEnumerable[[Product]]"/>

    <ul if="products.Any()">

      <li each="var p in products">${p.Name}</li>

    </ul>

    <else>

      <p>No products available</p>

    </else>

     
    En mi caso, todavía no he encontrado motivos suficientes como para dar el salto a un motor de vistas distinto de WebForms. Sinceramente, no me parece tan aberrante ver código y marcado dentro del mismo archivo, siempre teniendo en cuenta que la lógica que debe aparecer en estos puntos debe ser siempre relativa a la presentación y, por tanto, simplísima.

Opiniones aparte, la verdad es que es un interesante grupo de consejos a tener en cuenta.

Fuente: 12 ASP.NET MVC Best Practices

Crossposteado desde: 12 buenas prácticas en ASP.NET MVC | Variable not found  

El patrón Post-Redirect-Get

Hoy vamos a dedicar un rato a comentar una técnica que es considerada una buena práctica en el desarrollo de aplicaciones web: el patrón PRG o Post-Redirect-Get. Seguramente alguna vez lo haya citado por aquí, pero nunca lo había explicado en profundidad.

Por último, antes de entrar en materia, es conveniente indicar que lo que vamos a ver es válido para ASP.NET Webforms, ASP.NET MVC y, en general, para cualquier tecnología de construcción de sitios web que incluya componentes en servidor, puesto que se trata de una forma de hacer las cosas, no de la implementación de una solución. Ya en el último epígrafe veremos implementaciones concretas para Webforms y el framework MVC.

El problema

Es bastante habitual que al desarrollar aplicaciones para la web creemos un formulario de introducción de datos, y lo normal es que estos envíen los datos al servidor utilizando el verbo HTTP Post. Hasta aquí, bien.

Cuando desde el servidor se recibe una petición de este tipo normalmente se ejecuta un código, por ejemplo para almacenar la información en la base de datos y, de forma bastante frecuente, aprovechamos para enviar al cliente feedback de que su operación ha sido realizada con éxito. Y aquí es donde aparece el problema.

image Si el usuario, por esas ocurrencias que suele tener ;-), decide pulsar F5 o actualizar la página en el navegador, se van a producir dos efectos desagradables:

  • primero, se le mostrará al usuario un cuadro de diálogo informándolo de algo que difícilmente va a entender y que, en cualquier caso, le asustará bastante. El navegador le informa de que está realizando un reenvío completo de los datos del formulario.
  • segundo, una vez superado el escollo anterior, se volvería a ejecutar en servidor toda la lógica asociada a la recepción de datos del formulario con consecuencias, a veces terribles, como el almacenamiento de registros duplicados en la base de datos.

¿Cómo podemos evitar esto?

La solución: Post-Redirect-Get

El patrón PRG viene a indicarnos una forma de diseñar nuestras aplicaciones pensando en evitar los problemas descritos anteriormente, y, como veremos, es bastante simple. El procedimiento general a seguir sería:

  1. Recibimos la petición Post con los datos que ha introducido el usuario en un formulario.
  2. Ejecutamos la lógica asociada a la recepción de dicho formulario, por ejemplo, grabar en la base de datos.
  3. Enviamos al cliente una respuesta con código HTTP 30x (Redirect), indicando al agente de usuario que debe solicitar otra página, en la mostraremos un mensaje informando de que el proceso se ha realizado con éxito.
  4. El navegador obtiene dicha página mediante una petición de tipo Get.

En este punto, si el usuario decide (o el diablo que lleva dentro le ordena ;-)) refrescar la página, lo único que conseguirá será que su navegador vuelva a solicitar la página en la que le estamos informando de que el proceso ha sido satisfactorio. No se le muestra ningún cuadro de diálogo amenazante, ni se ejecuta la lógica de nuevo, ni hay ningún tipo de daños colaterales.

El siguiente diagrama, basado en el de la imprescindible Wikipedia, muestra gráficamente este proceso:

Secuencia en el patrón PRG

¿Un poco de código? Sí, por favor

ASP.NET WebForms

La abstracción sobre los protocolos montada por la tecnología Webforms hace más difícil reconocer los conceptos que estamos tratando, pero aún así es bastante sencillo aplicar el patrón.

En los formularios web, los postbacks se realizan a través de métodos Http POST, por lo que la implementación de la lógica y la redirección podremos realizarlas en la implementación del evento de servidor correspondiente, por ejemplo, el de pulsación de un botón:

protected void btnAceptar_Click(object sender, EventArgs e)

{

    if (Page.IsValid)

    {

        // Lógica 

        Cliente cliente = new Cliente(txtNombre.Text, txtApellidos.Text);

        GestorDeClientes.Salvar(cliente);

    

        // Redirección

        Response.Redirect("clientes.aspx", true);

    }

}

 

La página “clientes.aspx” podría ser ser el listado de clientes registrados en el sistema, por ejemplo.

ASP.NET MVC

En el framework MVC, por su cercanía a los protocolos, sí es fácil identificar los conceptos de petición y redirecciones. El siguiente código sería equivalente al anteriormente mostrado, pero enviando al usuario a la acción “Index”:

[HandleError]

public class ClientesController : Controller

{

    ... // Otras acciones

 

    [AcceptVerbs(HttpVerbs.Post)]

    public ActionResult Editar(Cliente cliente)

    {

        if (ModelState.IsValid)

        {

            GestorDeClientes.Grabar(cliente);

            return RedirectToAction("Index");

        }

        return View(cliente);

    }

}

Crossposteando desde: El patrón Post-Redirect-Get.

Publicado ASP.NET MVC 2 Beta

mvc-logo-landing-pageHace sólo unas horas Haack ha anunciado en su blog la publicación de la versión beta del  framework ASP.NET MVC 2, que tenemos a nuestra disposición tanto a nivel de código fuente como de instalador binario.

Echando un vistazo rápido a las release notes, las novedades son:

  • introducción de los nuevos métodos Html.RenderAction() y Html.Action(), el primero de ellos para escribir directamente la salida resultado de ejecutar la acción dada, y el segundo para obtenerla como cadena.
  • helpers para la generación de controles de edición en las vistas, basados en expresiones lambda o, en otras palabras, con tipado fuerte: ValidationMessageFor(), TextAreaFor(), TextBoxFor(), HiddenFor()y DropDownListFor().
  • mejoras en TempDataDictionary, destinadas a controlar de forma más pormenorizada la persistencia de los datos.
  • se incluyen las librerías de validación en cliente, MicrosoftAjax.js y MicrosoftMvcAjax.js. Para utilizar este automatismo, sólo hay que incluir ambos script en la vista (o master) e invocar al método de activación: <% Html.EnableClientValidation(); %>.
  • Visual Studio incorpora ahora una opción “Add Area” en el menú contextual, así como un cuadro de diálogo para crearlas.
  • es posible crear controladores de ejecución asíncrona heredando de la clase AsyncController. Esto permite crear acciones que se ejecuten en segundo plano, sin bloquear el hilo principal.
  • nueva plantilla de proyectos en blanco, es decir, sin toda la parafernalia de las plantillas actuales (páginas de ejemplo, autenticación, etc.).
  • capacidad para registrar múltiples proveedores de validación, permitiéndonos adoptar otras soluciones o frameworks, o crear nuestras propias opciones.
  • separación del proveedor de datos, el componente utilizado para obtener datos del contexto, en subcomponentes especializados en función del origen de la información (formularios, ruta, cadena de petición, y archivos). También existe la posibilidad de crear proveedores personalizados.
  • Y otras mejoras, de menor calado, citadas de forma concisa en las notas de la revisión, como:
    • adición de nuevos métodos y propiedades a la clase ModelMetadata.
    • cambios en la plantilla por defecto de las vistas para generar los controles utilizando los nuevos helpers.
    • helpers con soporte para datos binarios en el modelo, generando automáticamente campos ocultos codificados en Base64.
    • etc.

Y ojo, que esta beta sólo funciona con Visual Studio 2008 SP1, no podemos probarla con la última beta de Visual Studio 2010. Eso sí, puede convivir en nuestros equipos con MVC 1.0 sin interferencias.

El siguiente paso será la publicación de la RC, que está prevista “antes de finalizar el año”, aunque no se planea incluir funcionalidades nuevas, simplemente corregir bugs y pequeñas mejoras que puedan derivar de esta fase de pruebas y del feedback de los usuarios. Por tanto, en líneas generales, lo que nos trae esta beta será prácticamente lo que vendrá en la versión 2 🙂

Enlaces:

 Crossposteando desde: Publicado ASP.NET MVC 2 Beta | Variable not found  

Modifica el portapapeles de tus visitantes con ZeroClipboard

Si estás creando herramientas webs que generan código o texto para que tus visitantes lo copien y peguen en otras aplicaciones, ZeroClipboard puede facilitar su utilización, al permitir introducir el contenido que deseemos en el portapapeles de los usuarios.

image Hace tiempo ya comenté una forma de acceder transparentemente al portapapeles de los visitantes utilizando el objeto window.clipboardData, pero esta posibilidad desapareció, al menos en su versión silenciosa, conforme los navegadores fueron tomándose más en serio los temas de seguridad. A día de hoy, si intentamos utilizar estas funciones desde Explorer, aparece un cuadro de diálogo de confirmación algo molesto, para alertar al usuario de que el script de una página está intentando acceder a dicha información.

ZeroClipboard es una pequeña librería javascript que utiliza una película flash para acceder al portapapeles en modo “escritura”, es decir, para introducir en él un valor generado desde un script como respuesta a una acción del usuario como la pulsación de un botón o enlace. Podéis verlo en acción en esta demo online.

El siguiente código muestra cómo podemos utilizarlo. Creamos un <textarea> cuyo evento onchange aprovechamos para ir almacenando el contenido que pasará al portapapeles cuando el usuario pulse el enlace (btnCopiar) al que hemos vinculado este comportamiento:

 

<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<title>Prueba de ZeroClipboard</title>
<script type="text/javascript" src="ZeroClipboard.js"></script>
</head>
<body>
<textarea id="texto" rows="10" cols="10"
onchange
="clip.setText(this.value);"></textarea>
<br />
<a id="btnCopiar" href="#">Copiar</a>
</body>
<script type="text/javascript">
clip
= new ZeroClipboard.Client();
clip.glue(
'btnCopiar');
</script>
</html>

Si lo probáis, podréis ver que en ningún momento se alerta al usuario de que su portapapeles va a ser modificado, quedando muy limpio y profesional. 🙂

Crossposteando desde: Modifica el portapapeles de tus visitantes con ZeroClipboard

jqGrid: Grids espectaculares para ASP.NET MVC, paso a paso

Dicen las malas lenguas 😉 que durante una reunión del equipo de diseño de ASP.NET MVC alguien dijo: “necesitaremos un control tipo Repeater”, refiriéndose a algún tipo de mecanismo para mostrar datos tabulados de forma sencilla. Y la respuesta del jefe técnico fue, “ya lo tenemos: se llama bucle foreach”.

Anécdotas aparte, es cierto que en ASP.NET MVC 1.0 no existe otro mecanismo que el bucle de toda la vida para mostrar datos en tablas, la típica rejilla con información sobre elementos de una colección tan habitual en nuestras aplicaciones. La máxima ayuda que tenemos “de serie” es el andamiaje generado por Visual Studio a la hora de generar una vista sobre una enumeración de elementos, que es válida únicamente en escenarios muy sencillos.

Y aquí es donde entra jQuery Grid Plugin (jqGrid para los amigos), un plugin para jQuery que se integra perfectamente con ASP.NET MVC y que permite simplificar enormemente el desarrollo  de vistas de tipo grid ofreciendo al mismo tiempo unas funcionalidades espectaculares: paginación, carga de datos de forma asíncrona vía Ajax, ordenación y redimensionado de columnas, edición de celdas, interfaz multi-idioma basado en temas, y un larguísimo etcétera.

En este post vamos a implementar un grid simple de consulta de datos utilizando jqGrid 3.5 y ASP.NET MVC 1.0, paso a paso. Además, al final del post encontraréis un enlace para descargar el proyecto de demostración para Visual Studio 2008 Express.

1. Descargamos jqGrid

Descarga de jqGridLo primero, como siempre, es descargar los componentes necesarios. Para hacernos con jqGrid, es necesario visitar la página de descargas del proyecto, en la que podemos encontrar un selector que nos permitirá elegir los módulos asociados a las funcionalidades que vayamos a utilizar.

En nuestro caso, dado que vamos a implementar un escenario muy simple, seleccionaremos únicamente el módulo “Grid base” y pulsamos el botón download situado en el pie de la tabla.

La descarga es un archivo .zip bastante ligerito cuyo contenido utilizamos así:

  • jquery.jqGrid.min.js, que encontraréis en la carpeta “js” del archivo descargado, lo copiamos a la carpeta “scripts” del proyecto ASP.NET MVC.
  • grid.locale-sp.js , el archivo de localización al español que encontraremos en la carpeta “js/i18n” del .zip, lo copiamos también a la carpeta “scripts” del proyecto.
  • ui.jqgrid.css , disponible en la carpeta “css” del archivo comprimido, lo pasamos a la carpeta “content” del proyecto.

Archivos del proyecto 2. Descargamos un tema visual

jqGrid utiliza los temas visuales de jQuery UI para componer el interfaz, por lo que es necesario descargar alguno de los disponibles o bien crear uno personalizado con la herramienta on-line disponible en su página. Para nuestro ejemplo, vamos a utilizar el tema “Cupertino”.

Como en el caso anterior, seleccionamos los componentes a obtener (en principio, basta con UI Core a no ser que vayáis a utilizar esta librería para otras cosas), el tema, y pulsamos el botón download. Descargaremos un archivo .zip en cuyo  interior encontramos, dentro de la carpeta “css”, una subcarpeta con el nombre del tema elegido y que copiamos a la carpeta “content” del proyecto MVC.

La imagen anterior muestra la distribución de los archivos descritos hasta el momento en las distintas carpetas en las que hay que colocarlos.

3. Incluimos los componentes en el proyecto ASP.NET MVC

Tras crear el proyecto ASP.NET MVC, vamos a incluirle ahora las referencias a librerías y archivos necesarios para poder utilizar jqGrid.

Básicamente, tendremos que incluir en las páginas donde vayamos a utilizarlo referencias a jQuery, jqGrid, el archivo de localización, la hoja de estilos utilizada por jqGrid, y el tema que estemos empleando. Lo más fácil es hacerlo a nivel de página maestra, por ejemplo así:

<head runat="server">

    <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>

    <link href="../../Content/Site.css" rel="stylesheet" type="text/css" />

 

    <link href="../../Content/ui.jqgrid.css" rel="stylesheet" type="text/css" />

    <link href="../../Content/cupertino/jquery-ui-1.7.2.custom.css" 

          rel="stylesheet" type="text/css" />

    <script src="../../Scripts/jquery-1.3.2.min.js" type="text/javascript"></script>

    <script src="../../Scripts/grid.locale-sp.js" type="text/javascript"></script>

    <script src="../../Scripts/jquery.jqGrid.min.js" type="text/javascript"></script>

</head>

Es importante incluir todos los archivos y en el orden correcto, de lo contrario el plugin no funcionará correctamente.

4. El modelo

En lugar de utilizar una base de datos, vamos a crear una simulación en memoria de un almacén de datos personales basado en la siguiente entidad:

public class Amigo

{

    public int Id { get; set; }

    public string Nombre { get; set; }

    public string Apellidos { get; set; }

    public DateTime FechaDeNacimiento { get; set; }

    public string Email { get; set; }

}

La lógica de negocio está implementada en la clase GestorDeAmigos, que incluye, además del constructor que carga los datos iniciales en el almacén (una colección de tipo List<Amigo> , los siguientes métodos:

public IEnumerable<Amigo> ObtenerAmigos(int pagina, int elementosPorPagina, 

                                        Func<Amigo, IComparable> orden, 

                                        Ordenacion ordenacion)

{

    IEnumerable<Amigo> datos;

    if (ordenacion==Ordenacion.Ascendente)

        datos = datosAmigos.OrderBy(orden);

    else

        datos = datosAmigos.OrderByDescending(orden);

 

    return datos.Skip((pagina - 1) * elementosPorPagina).Take(elementosPorPagina);

}

 

public int ContarAmigos()

{

    return datosAmigos.Count;

}

Del código anterior, sólo comentar los parámetros del método ObtenerAmigos:

  • pagina y elementosPorPagina, indican, respectivamente el número de página de datos a mostrar y el número de registros máximo a mostrar en cada una de ellas.
  • orden es una lambda que retorna la expresión por la cual ordenaremos los datos. Si estuviéramos utilizando consultas SQL directas o LINQ to SQL podríamos usar otros enfoques, como la construcción de queries dinámicas o Dynamic LINQ.
  • ordenacion indica, usando una enumeración, si el orden es ascendente o descendente.

Así, a continuación puede verse un ejemplo de lo simple que quedaría una llamada a este método, flexible pero con tipado fuerte:

var amigos = gestorDeAmigos.ObtenerAmigos(

                   1,                       // Página actual

                   25,                      // Registros por página

                   amigo=>amigo.Apellidos,  // Expresión de ordenación

                   Ordenacion.Ascendente    // Orden

             );

5. El controlador

Una de las principales ventajas que ofrece jqGrid es que la carga de los datos la realiza mediante peticiones Ajax. En la práctica, esto significa que irá lanzando llamadas a una acción de nuestro controlador para solicitarle la información conforme vaya necesitando datos, por ejemplo, durante la carga inicial de la página o cuando el usuario utiliza las herramientas de paginación, enviándole los siguientes parámetros:

  • sidx, el índice o nombre del campo de ordenación actual.
  • sord, “asc” o “desc”, indicando si el orden es ascendente o descendente.
  • page, el número de página actual.
  • rows, número de elementos a obtener para completar la página.

El retorno de este método de acción debe ser un objeto serializado en JSON (aunque también permite XML) y ha de ajustarse a un formato especificado en la documentación, que es el que jqGrid espera recibir, algo como:

{ 

  total: "xxx", 

  page: "yyy", 

  records: "zzz",

  rows : [

    {id:"1", cell:["cell11", "cell12", "cell13"]},

    {id:"2", cell:["cell21", "cell22", "cell23"]},

      ...

  ]

}

El método de obtención de datos,  nuestra acción, seguirá normalmente el patrón recogido en el código mostrado a continuación. Si os fijáis, lo único que estamos haciendo es reproducir fielmente esta estructura anterior en un objeto anónimo, de forma que  al transformarlo en JSON (gracias al retorno de tipo JsonResult) se genere justo lo que necesitamos:

public ActionResult ObtenerDatosGrid(string sidx, string sord, int page, int rows)

{

    var datos = [...]          // Obtener datos del modelo

    var totalRegistros = [...] // Contar todos los registros

 

    int totalPages = (int)Math.Ceiling((decimal)totalRegistros / (decimal)rows);

 

    var data = new

    {

        total = totalPages,        // Total de páginas

        page = page,               // Página actual

        records = totalRegistros,  // Total de registros (obtenido del modelo)

        rows = from a in datos     // Datos de filas

               select new {

                   id = a.Id,                // ID único de la fila

                   cell = new string[] {     // Array de celdas de la fila

                       a.Apellidos,                             // Primera columna,            

                       a.Nombre,                                // Segunda columna,

                       a.FechaDeNacimiento.ToShortDateString(), // Tercera columna,

                       a.Email                                  // Cuarta columna  

                   }

               }

    };

    return Json(data);

}

Nuestro ejemplo se ajusta totalmente al patrón anterior, aunque incluiremos código extra para tener en cuenta las ordenaciones indicadas por los parámetros sidx y sord en la invocación al modelo. Observad cómo construimos las expresiones de ordenación:

public ActionResult ObtenerDatosGrid(string sidx, string sord, int page, int rows)

{

    // Establecemos la función de ordenación dependiendo del valor del 

    // parámetro "sidx", que es el campo de orden actual

    Func<Amigo, IComparable> funcOrden =

        sidx == "Apellidos" ? a => a.Apellidos :

        sidx == "FechaDeNacimiento" ? a => a.FechaDeNacimiento :

        sidx == "Email" ? a => a.Email :

        (Func<Amigo, IComparable>)(a => a.Id);

 

    // Establecemos si se trata de orden ascendente o descendente, en

    // función del parámetro "sord", que puede valer "asc" o "desc"

    Ordenacion ordenacion = sord == "asc" ? Ordenacion.Ascendente : Ordenacion.Descendente;

 

    // Usamos el modelo para obtener los datos

    var datos = gestorDeAmigos.ObtenerAmigos(page, rows, funcOrden, ordenacion);

    int totalRegistros = gestorDeAmigos.ContarAmigos();

    ... 

}

6. La vista

En la vista debemos crear un elemento contenedor, concretamente una tabla XHTML con un identificador único que después usaremos para indicarle al plugin dónde tiene que actuar su magia. Si además, como bastante habitual, pensamos incluir herramientas de paginación, tendremos que incluir también un contenedor para la misma:

<table id="list"></table>

<div id="pager"></div>    

El siguiente paso es inicializar jqGrid cuando se termine de cargar la página, para lo que crearemos un código javascript como el mostrado a continuación, en el que se invoca la función de activación del plugin sobre la tabla cuyo ID se indica en el selector (“#list“), y especificando el comportamiento deseado en los parámetros que le siguen:

script type="text/javascript">

    jQuery(document).ready(function() {

        jQuery("#list").jqGrid({

            url: '<%= Url.Action("ObtenerDatosGrid") %>',

            datatype: 'json',

            mtype: 'GET',

            colNames: ['Apellidos', 'Nombre', 'Fecha Nac.', 'Email'],

            colModel: [

              { index: 'Apellidos', width: 150, align: 'left' },

              { index: 'Nombre', width: 150, align: 'left', sortable: false },

              { index: 'FechaDeNacimiento', width: 80, align: 'center' },

              { index: "Email", width: 120, align: 'left'}],

            pager: jQuery('#pager'),

            rowNum: 20,

            rowList: [20, 50, 100],

            sortname: 'Apellidos',

            sortorder: 'asc',

            viewrecords: true,

            imgpath: '/content/cupertino/images',

            caption: 'Agenda personal',

            height: 400,

            width: 900,

            onSelectRow: function(id) {

                alert("Pulsado Id: " + id);

            }

        });

    }); 

</script>    

Revisamos rápidamente el significado de los distintos parámetros:

  • url, la dirección de la acción que suministrará los datos.
  • datatype, que indica el formato de intercambio de datos.
  • mtype , el verbo HTTP (get o post) que se utilizará para las peticiones.
  • colnames, un array con los títulos de las columnas.
  • colmodel, un array en el que cada elemento es un objeto que define
    • index: el nombre del campo que recibiremos en el método de acción indicando la ordenación actual.
    • width: el ancho, en píxeles.
    • align: alineación de la columna.
    • sortable: si la columna se puede utilizar como criterio de ordenación.
  • pager, el elemento sobre el que se compondrá la herramienta de paginación.
  • rownum, número de elementos por página.
  • rowlist, elementos por página mostrados en un desplegable para que el usuario lo ajuste.
  • sortname, el campo de ordenación por defecto.
  • sortorder, si la ordenación por defecto es ascendente o descendente.
  • viewrecords, si se muestra el total de registros en la herramienta de paginación.
  • imgpath , ruta hacia la carpeta de imágenes del tema elegido.
  • caption, el título del grid.
  • height, width, alto y ancho del grid, en píxeles.
  • onSelectRow, función anónima ejecutada cuando el usuario selecciona una fila. Recibe como parámetro el identificador único del registro.

Y… ¡Voilá!

Demo de jqGrid en acción¡Hasta aquí hemos llegado! Hemos visto cómo utilizar el magnífico jqGrid en un escenario simple, paso a paso, comenzando por la descarga de los componentes, preparando el proyecto para poder utilizarlos y, finalmente, implementando el modelo, el controlador, y la vista.

Pero jqGrid no es sólo eso, ni mucho menos. No hemos visto más que la punta del iceberg: el plugin permite realizar búsquedas, edición, anidación de grids, árboles, escenarios maestro-detalle… en fin, una maravilla.

jqGrid se distribuye bajo licencia dual GPL y MIT, y puede ser utilizado tanto en proyectos comerciales como libres. Dispone de una documentación bastante razonable, y muchos ejemplos para que podamos apreciar sus virtudes.

Descargar proyecto de demostración:

Publicado en: Variable not found.

Variable not found en Facebook

Antes se solía decir que si no estabas en Internet, no existías; ahora que todo el mundo está en Internet, parece ser que si no estás en las redes sociales no existes. Cosas de la evolución, supongo 😉

Y aunque no soy muy amigo de este tipo de afirmaciones, por si acaso, en un auténtico alarde de socialización, he creado el sitio Variable not found en Facebook, que pongo a vuestra disposición para mantenernos en contacto de una forma algo más bidireccional de lo acostumbrado:

Variable not found en Facebook

Espero que nos veamos también por allí. 🙂

Publicado en: Variable not found.