miércoles, 27 de junio de 2012

ASP.NET 4.0 y Ajax - Desarrollar una página de búsqueda y edición dinámica de contenido usando JQuery/JSON

ASP.NET 4.0 incluye varios componentes que nos permiten trabajar con Ajax en nuestras páginas:
  • ASP.NET AJAX Server controls
  • Microsoft Ajax Library
  • Ajax Control ToolKit
  • JQuery

En este artículo nos centraremos en JQuery, desarrollaremos a modo de tutorial una búsqueda de películas que nos permita filtrar en base a un par de criterios y editar algún elemento de la lista.

JQuery es una librería javascript que nos proporciona atajos y funciones para seleccionar, manipular y animar elementos del DOM. Por otro lado incorpora métodos Ajax que facilitan este tipo de comunicación entre código cliente y servidor. JQuery está soportado por todos los navegadores actuales y es compatible con cualquier plataforma servidor que permita comunicación JSON.

En el ejemplo usaremos JQuery para mostrar el resultado de la búsqueda en una tabla HTML e implementaremos 2 llamadas a servidor intercambiando información de tipo JSON. Para más información sobre la API ver la página oficial donde se puede consultar una referencia de la librería y hacernos una idea de lo que se puede llegar a hacer con JQuery.

Usaremos Microsoft Visual Web Developer 2010 Express para crear un sitio web ASP.NET vacío y añadiremos los siguientes archivos al proyecto:
  • Web Form (Pelicula.aspx): Contendrá los filtros, la tabla de resultados y la ficha de edición.
  • Archivo JScript(JScript.js): Contendrá nuestros scripts JQuery.
  • Hoja Estilos (StyleSheet.css): Ubicaremos los estilos que se aplican en la página.
  • Clase (DataPelicula.cs): En la carpeta AppCode, crearemos objetos que simulan un acceso a datos en servidor y nuestro modelo de datos.

No me gustaría que el artículo sea más denso de lo necesario así que no dedicaremos demasiado tiempo al acceso a datos en servidor. Hay varias alternativas para acceder a datos desde nuestra página WCF, Entity Framework, ADO, LINQ, (...) aquí simularemos que nuestra página comunica con un objeto ubicado en AppCode que incluye 2 funciones públicas, una para obtener películas y la otra para actualizar una película.


Una vez tenemos el acceso a datos y nuestra clase Película que usaremos en la comunicación entre cliente y servidor, desarrollaremos la página Pelicula.aspx. La página se estructura en Búsqueda, Lista, Ficha y Scripts de Servidor.
  • Búsqueda: Añadiremos 2 labels y 2 elementos input, si usamos componentes asp sería recomendable desactivar la característica viewstate o bien usar directamente elementos input html para evitar tags innecesarios en el documento final en cliente. Es importante asignar ID a los elementos con los que trabajaremos en los scripts de cliente ya que simplificarán el trabajo posteriormente.
  • Lista: Añadiremos una tabla con una sola fila con id="Cabecera" y tantas columnas como atributos tenga nuestro objeto Película.
  • Ficha: Añadiremos labels y campos para la edición de una película. Más adelante aplicaremos un estilo a esta capa para que esté oculta por defecto y jugaremos con la característica z-index de las capas para sobreponer el div ficha al resto cuando estemos en modo edición.
  • Scripts de Servidor: JQuery mediante la función puede comunicar directamente contra Scripts ubicados en la página o contra servicios svc,asmx que estén correctamente configurados para recibir contenido JSON vía HTTP. Trataremos el tema de servicios más a fondo en futuros artículos en la sección WCF de este mismo blog!. Sigue nuestros RSS para recibir avisos con nuevas publicaciones que puedan interesarte
    En nuestro caso implementaremos las funciones de servidor en WebMethods dentro de nuestra página aspx ya que es más sencillo y óptimo en este caso. Nos podría interesar comunicar contra servicios web en una arquitectura orientada a servicios.
    Como veréis el WebMethod GetPeliculas devuelve una lista de objetos de tipo Pelicula y el UpdatePelicula recibe un objeto de tipo Pelicula.

Aquí podéis ver un ejemplo de como quedaría la página Pelicula.aspx (no añadimos código servidor en Pelicula.cs):
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Pelicula.aspx.cs" Inherits="Pelicula" %>
<!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">
    <link href="StyleSheet.css" type="text/css" rel="Stylesheet" />
    <script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js" type="text/javascript"></script>
    <script src="JQueryUtils.js" type="text/javascript"></script>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div id="Busqueda">
        <div id="Filtros">
            <div><label for="Referencia">Nombre :</label><input type="text" id="txtNombre" /></div><br />
            <div><label for="Categoria">Categoría :</label>
            <select id="selCategoria">
                <% string[] s = Enum.GetNames(typeof(VideoClub.Data.Categoria));
                   for (int i = 0; i <= s.GetUpperBound(0); i++)
                       Response.Write(string.Format("<option>{0}</option>",s[i]));
                 %>
            </select>
            </div><br />
            <input type="button" value="Buscar" onclick="javascript:RecargarTabla();"/> 
        </div>

        <div id="Lista">
            <table id="TablaResultado" border="1" cellpadding="4" cellspacing="2">
                <tr id="Cabecera"><td>Referencia</td><td>Nombre</td><td>Categoría</td></tr>
            </table>
        </div>
    </div>
        
    <div id="Ficha" class="Ficha">
        <div><label for="Referencia">Referencia :</label><input type="text" id="Referencia"/></div><br /><br />
        <div><label for="Nombre">Nombre :</label><input type="text" id="Nombre"/></div><br /><br />
        <div><label for="Categoria">Categoría :</label><input type="text" id="Categoria"/></div><br /><br />
        <div><input type="hidden" id="Codigo" /></div>
        <br />
        <input type="button" value="Guardar" onclick="javascript:ActualizarCambios()" />
    </div>

    </form>

    <script runat="server">
        [System.Web.Services.WebMethod]
        public static List<VideoClub.Data.Pelicula> GetPeliculas(string pNombre, string pCategoria)
        {
            try
            {
                VideoClub.Data.Pelicula filter = new VideoClub.Data.Pelicula();
                filter.Categoria = pCategoria;
                filter.Nombre = pNombre;

                return new VideoClub.Data.DataPelicula().Get(filter);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        [System.Web.Services.WebMethod]
        public static void UpdatePelicula(VideoClub.Data.Pelicula pelicula) 
        {
            try 
            {
                new VideoClub.Data.DataPelicula().Update(pelicula);
            }
            catch (Exception ex) 
            {
                throw ex;
            } 
        }
    </script>
</body>
</html>
No entraré a comentar la hoja de estilos, más abajo podéis descargar el código fuente del ejemplo.

Vamos a desarrollar nuestro archivo .js donde veremos la parte de JQuery, antes de nada fijémonos en el tag head de nuestra página:
<script src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js" 
type="text/javascript"></script>
<script src="JQueryUtils.js" type="text/javascript"></script>
El primero hace referencia a la librería JQuery. Se puede referenciar una URL externa (CDN) o se puede añadir directamente el archivo .js de la librería manualmente al proyecto y referenciarlo. No notaremos diferencia en este caso pero de cara a una aplicación corporativa mejor usar URL externa porque interviene la caché y siempre es más rápida la descarga.

Nota: Al crear una nueva solución con Visual Studio, depende de la selección inicial puede ser que el proyecto incorpore por defecto la referencias a Jquery Library. En nuestro caso hemos seleccionado aplicación web vacía por tanto ha sido necesario añadir la referencia manualmente y hemos optado por hacer una referencia externa.

Lo primero crearemos una función CambiaCursor() en el .js que vincularemos posteriormente a eventos onmouseover/onmouseout de las filas que pintaremos.
function CambiaCursor() {
    if (document.body.style.cursor == 'pointer')
        document.body.style.cursor = 'default';
    else
        document.body.style.cursor = 'pointer';
}
Crearemos otra función que se encargará de buscar los valores de los filtros por el DOM y pasarlos como parámetros al script GetPeliculas que hemos creado en el lado servidor para posteriormente dibujar en nuestra tabla tantos elementos TR como elementos nos devuelva la llamada.
Explico por encima las intrucciones JQuery que usamos aquí:
  • $("#txtNombre").val(); => Selector por ID, devuelve el elemento del DOM asociado al id. Está permitido anidar y combinar instrucciones de selección, manipulación y demás con lo que si dominamos la sintaxi podemos hacer lo que imaginemos con el contenido HTML.
  • $.ajax(); => comunica con un script de servidor:
    • data: Permite pasar parámetros de entrada a la función servidor
    • succes: Permite definir un objeto data que contendrá la respuesta del servidor que en este caso devuelve una lista de objeto Película que tendrá los mismos atributos que nuestro objeto servidor gracias a la serialización JSON del contenido. Además nos permite implementar código JQuery en este caso para añadir tantos TR como filas nos haya devuelto nuestra consulta servidor.
    • error: En este caso el método servidor devolverá un objeto Exception en caso de producirse algún error en servidor. Podemos usar el método parseJSON() para deserializar la respuesta en una función cliente y mostrar la información que nos convenga por pantalla. En este caso mostramos la propiedad Message con una alerta.
function RecargarTabla() {
    //obtenemos valores de filtros
    var nombre = $("#txtNombre").val();
    var categoria = $("#selCategoria").val();
    
    //llamada al script servidor
    $.ajax({
        type: "POST",
        dataType: "json",
        contentType: "application/json",
        url: "Pelicula.aspx/GetPeliculas",
        data: "{'pNombre':'" + nombre + "','pCategoria':'" + categoria + "'}",
        success: function (data) {
            var peliculas = data.d;
            //eliminamos los  que puedan haber despues del '' (anteriores búsquedas)
            $("#Cabecera").nextUntil("table").remove();
            //guardamos respuesta en variable peliculas y añadimos una fila por elemento del array después del tag ''.
            $.each(peliculas, function (i, item) { $("#Cabecera").after("" + item.Referencia + "" + item.Nombre + "" + item.Categoria + ""); });
        },
        error: function (response) { 
            var ex = $.parseJSON(response.responseText);
            alert("Error : " + ex.Message);
            //podríamos acceder a las propiedades del objeto Exception que se ha generado en servidor (ex.StackTrace, ex.InnerException, ex.ExceptionType...) 
        } 
    });
}
La siguiente función que crearemos se lanzará al hacer clic en una fila y se encargará de recuperar los valores del TR que ha lanzado el evento, asignarlos a los campos de la ficha y mostrar con fadeIn() la capa con id="Ficha". Si nos adentramos un poco más en la referencia de JQuery seguramente veremos que hay métodos más óptimos y elegantes para obtener los valores de las celdas en este caso. Se agradecen aportaciones y comentarios!
function Editar(pID) {
    //seleccionamos la fila entera, recuperamos los valores y los asignamos a los campos de la ficha
    var selector = "#" + pID;
    $("#Codigo").val(pID);
    $.each($(selector).find("td"), function (i, celda) {
        switch (i) {
            case 0:
                $("#Referencia").val(celda.innerText);
            case 1:
                $("#Nombre").val(celda.innerText);
            case 2:
                $("#Categoria").val(celda.innerText);
        }
    });
            
    //mostramos la ficha
    $("#Ficha").fadeIn("slow"); 
}
Ya para acabar creamos ActualizarCampos que se lanzará al pulsar el evento clic del botón Guardar que hemos ubicado en la ficha de Película. La función se encarga de buscar los valores de la ficha, componer un objeto con el formato adecuado para que nuestro servidor sea capaz de parsearlo contra la clase Película, realizar la llamada Ajax al método UpdatePelicula de servidor y actualizar la tabla con los valores que han cambiado. En este método usamos JSON.stringify para aplicar la serialización JSON aunque existen alternativas para dar formato JSON a los parámetros de entrada.
function ActualizarCambios() {
    //obtener valores de la ficha
    var nombre = $("#Nombre").val();
    var categoria = $("#Categoria").val();
    var referencia = $("#Referencia").val();
    var codigo = $("#Codigo").val();

    //componer parámetro entrada UpdatePelicula en servidor
    var pelicula = { 'Codigo': codigo, 'Referencia': referencia, 'Nombre': nombre, 'Categoria': categoria };
    var Pelicula = { 'pelicula': pelicula };

    //llamada servidor
    $.ajax({
        type: "POST",
        dataType: "json",
        contentType: "application/json",
        url: "Pelicula.aspx/UpdatePelicula",
        data: JSON.stringify(Pelicula),
        success: function () {
        },
        error: function (response) {
            var ex = $.parseJSON(response.responseText);
            alert("Error : " + ex.Message);
            //podríamos acceder a las propiedades del objeto Exception que se ha generado en servidor (ex.StackTrace, ex.InnerException, ex.ExceptionType...) 
        }
    });

    //actualizar fila con los nuevos valores
    var selector = "#" + codigo;
    $(selector).replaceWith("" + referencia + "" + nombre + "" + categoria + "");

    //ocultar ficha
    $("#Ficha").fadeOut("slow"); 
}
Espero os haya resultando interesante, más adelante publicaremos alguno relacionado con otro componente Ajax de los mencionados al inicio para realizar el mismo ejemplo de película y así poder valorar un poco aspectos interesantes de cada uno de los componentes AJAX que incorpora ASP.NET 4.0.

Os dejo un enlace donde podréis descargar la solución que hemos creado en el ejemplo y os recomiendo una serie de lecturas interesantes que podéis adquirir si os interesa profundizar en el tema. Dentro de areaTIC puedes encontrar otros artículos interesantes, no dudes en consultar nuestro archivo.

AreaTIC, ASP.NET, Ajax, JQuery, JSON   Descargar código de ejemplo



LECTURAS RELACIONADAS RECOMENDADAS POR AREATIC.NET

1 comentario:

Anónimo dijo...

An outstanding sharе! I've just forwarded this onto a coworker who has been conducting a little research on this. And he in fact bought me lunch because I stumbled upon it for him... lol. So allow me to reword this.... Thank YOU for the meal!! But yeah, thanks for spending some time to talk about this subject here on your internet site.
Also see my webpage > top 10 seo companies in the world

Publicar un comentario