martes, septiembre 22, 2009

Update Progress Solution for ASP.NET MVC with Ajax

Etiquetas de Technorati: ,,,,,
Introducción
Buscando alternativas para utilizar ajax y un estilo como el de update progress de ASP.NET para ASP.NET MVC me encontré con algunas soluciones que no eran lo que buscaba, algunas mezclando componentes de servidor otras con código demasiado abstracto para algo que debería ser simple.
Finalmente decidí hacerlo de otro modo y obtuve esta solución simple basada directamente y exclusivamente, en lo que ofrece ASP.NET MVC. El concepto que propongo está basado en MVC y proporciona control total sobre lo que queremos que se muestre. Es objetivo de este artículo generar una solución base los más directa posible con los controles existentes de MVC para facilitar la comprensión, con menos abstracciones, tal como se muestra a continuación.
Audiencia
Si usted no tiene conocimiento previo sobre los conceptos básicos de ASP.NET MVC le recomiendo revisar los mismos.
Lo que queremos lograr

Veamos primero lo que queremos obtener.
El usuario hace clic en la liga “Actualizar foo…”
image
El sistema pide su confirmación.
image
El usuario acepta y se procede con la actualización mostrando una imagen animada.image
Al finalizar el procedimiento de actualización se muestra un mensaje de “actualización lista” (Ready.).
image
En una vista cualesquiera (sea de un control de usuario o vista final) se crea un control de usuario llamado UpdateProgressControl y se inicializa su modelo UpdateProgressViewModel con un nombre de negocio que lo identifique “UpdateFoo”, el nombre debe ser válido para un control pero sólo basta con que contenga el sentido de negocio (los prefijos y/o sufijos como para un control, por ejemplo “divUpdateProgressUpdateFoo” los coloca el propio modelo).
Veamos una vista con un vínculo ajax (liga, link) y los elementos comentados.

<p>
<% =Ajax.ActionLink("Actualizar foo..."
, "Update1"
, new AjaxOptions()
{
Confirm
= "¿Seguro desea proceder con la actualización?"
, OnBegin
= UpdateProgressViewModel.GetFunctionNameForShow(
"UpdateFoo")
, OnComplete
= UpdateProgressViewModel.GetFunctionNameForHide(
"UpdateFoo")
}
) %>
</p>
<% Html.RenderPartial("UpdateProgressControl"
, new UpdateProgressViewModel("UpdateFoo")); %>



Como se observa en el código, mediante AjaxOptions se establecen los nombres de las funciones javascripts, utilizando métodos estáticos del propio modelo que reciben como parámetro el nombre simple de negocio que hemos definido antes (“EditFoo”). Más adelante se verán los detalles.


En resumen, el concepto central es simplemente:




  1. Crear el control de usuario UpdateProgressControl.


  2. Configurar los métodos OnBegin y OnComplete de AjaxOptions para mostrar y ocultar el control.



Además podemos colocar las características o estilo de nuestro control en un Cascading Style Sheets, CSS de nuestro sitio.



Índice



  1. Crear estilos (CSS).


  2. Crear un modelo para la vista.


  3. Crear la vista del control UpdateProgress.


Veamos cada punto en el mismo orden.




1. Crear los estilos.


Creamos un conjunto de estilos que utilizará nuestro control y nos permite modificar la presentación del mismo.



/* Update Progress  
----------------------------------------------------------*/
.updateProgress
{
display: none;
background-repeat: no-repeat;
background-image: url('../Content/Images/ajax-loader.gif');
padding-top: 5px;
padding-bottom: 20px
}
.updateProgress label
{
padding-left: 45px
}


2. Crear un modelo para la vista.

El modelo cuenta con:





  1. Varios constructores.


  2. Dos funciones estáticas para recuperar (y generar) los nombres de funciones de java script que se utilizarán para mostrar y ocultar la operación en progreso.


  3. Varias propiedades básicas (ID, Name y Message) para utilizarlas en el control.



image   
A continuación se muestra solamente el constructor más simple que inicializa valores predeterminados.



/// <summary>
///
Initialize update progress with default message.
/// </summary>
/// <param name="name">
Update progress name.</param>
public UpdateProgressViewModel(string name)
: this(name, UpdateProgressViewModel.GetInProgressMessage(), false)
{
}


3. Crear la vista del control UpdateProgress.


Ahora creamos la vista parcial del control Update Progress que utilizará el modelo previamente creado.

La vista integra los estilos definidos, unas rutinas de javascript y el modelo para generar un control simple html que se desplegará y ocultará a conveniencia durante las llamadas ajax de nuestras páginas consumidoras.


Nuestro control de usuario tiene dos DIV para desplegar nuestra imagen de actualización y para desplegar el mensaje de actualización terminada. El modelo es el encargado de generar los nombres o ID's que necesitemos.



Este primer DIV es para desplegar la imagen de actualización y se carga desde el CSS.



<div id="<%=Model.ID%>" class="updateProgress" style="display: none">
<
label>
<%= Html.Encode(Model.Message) %>
</label>
</
div>



El segundo DIV se encarga de desplegar un mensaje de actualización completada (Ready).



<div id="<%=Model.ID%>MessageResult" class="updateProgressResult" style="display: none">
<
label>
<%= SmartResource.GetString("ReadyLabel", "Ready.") %>
</label>
</
div>



Se puede sustituir la línea de “<%= SmartResource…” por un mensaje fijo.

Finalmente nuestro control de usuario mediante el modelo también genera el javascript que necesitamos para mostrar y ocultar nuestro control. Por ejemplo para mostrar el control y tenemos:



function <%=Model.FunctionNameForShow%>() {
$("#<%=Model.ID%>").show();
$("#<%=Model.ID%>MessageResult").hide();
var disableSubmit
= <%=Model.DisableSubmitOnRequestString %>;
if(disableSubmit)
{
//Disable submits.
$(":submit").each(
function (i)
{
this.disabled = true;
}
);
}
}



Como se observa estamos aprovechando las facilidades de jQuery para referenciar los elementos que queremos controlar.


En una próxima entrega podríamos explorar las ventajas de adicionar más abstracción a este tema y generar un MVC AjaxHelper especializado para este control que tanta utilidad tiene, lo que simplificaría aún más la llamada desde el cliente. En vez de utilizar el Ajax.ActionLink, sería tan simple como esto:


<p>

   
<%=Ajax.UpdateProgressLink("Actualizar foo helper..."

         
, "Update1"

         
, "¿Seguro desea proceder con la actualización?"

         
, "UpdateFoo") %>

</p>



---(Fin)---

No hay comentarios.: