por Ing. Juan Pablo Ibañez
http://ing.juanpablo.googlepages.com
Con la aparición de AJAX, ahora podemos cargar ciertas partes de una página ASPX sin tener que recargar toda la página. El problema surge cuando en una página queremos incluir diferentes funcionalidades que habitualmente están en páginas separadas. Si intentamos incluir todas las funcionalidades en nuestra página e ir cargándolas mediante AJAX, nuestra página comienza a hacerse demasiado grande para poder albergar todo el código que permite cambiar las partes y mostrar las distintas funcionalidades sin recargar toda la página. Hay aplicaciones grandes que requieren utilizar otro enfoque, como ser cargar páginas ASPX dentro de páginas ASPX pero sin hacer PostBack de la página contenedora. La técnica explicada en este artículo nos permite tener nuestra aplicación dividida en todas las páginas ASPX que necesitemos, y cargarlas dentro de una página contenedora usando AJAX, lo cual nos permite dividir mejor la funcionalidad, distintos equipos pueden trabajar independientemente en cada página ASPX, nuestra aplicaciones está mas desacoplada, prolija y demás beneficios.
En el siguiente ejemplo voy a mostrar como cargar diferentes ASPX dentro de otra página ASPX haciendo uso de AJAX WebServices. La imagen [Imagen1] que vemos a continuación es un esquema de lo que se pretende hacer.
[Imagen1]
La página contenedora tiene 1 div donde se insertará mediante AJAX el HTML de las páginas ASPX que se quieran cargar dinámicamente dentro de la página contenedora. Si nuestras ASPX que queremos cargar tiene elementos que hacen PostBack, debemos cargarlas dentro de un iframe, de lo contrario, por ejemplo, al presionar un Button en la página que se cargo dentro de la contenedora, se hará un PostBack que recargará también nuestra contenedora y la idea es que la contenedora nunca se recargue completamente.
Nuestra solución entonces deberá tener al menos los componentes que se muestran en la siguiente imagen [Imagen2].
- Default.aspx, nuestra página contenedora.
- Default.js, código Javascript para hacer la llamada al WebService y cargar el contenido que este devuelve en nuestro div.
- Page1.aspx, una de las páginas que queremos cargar dentro de Default.aspx
- Page2.aspx, otra de las páginas que queremos cargar dentro de Default.aspx
- PageLoader.asmx, el WebService que devuelve el HTML que vamos a cargar dentro del DIV de Default.aspx
- web.config, configuración para hacer uso de las librerías de AJAX ASP.NET y configuración para usar AJAX ASP.NET WebServices.
- ajax-loader.gif, imágenes que mostramos mientras se cargan las páginas interiores.
[Image2]
La idea es que nuestra página Default.aspx tenga un DIV donde cargar el HTML de las páginas que queremos cargar, haga una llamada a un AJAX Enabled WebService y mientras se carga la página interior muestre un Loading...
La estructura de nuestra página Default.aspx sería algo así:
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Path="Default.js" />
</Scripts>
<Services>
<asp:ServiceReference Path="PageLoader.asmx" />
</Services>
</asp:ScriptManager>
<div align="center">
<h2>Página Contenedora</h2>
<input id="btnLoadPage1" type="button" value="Cargar Página 1" onclick="return btnLoadPage1_onclick()" />
<input id="btnLoadPage2" type="button" value="Cargar Página 2" onclick="return btnLoadPage2_onclick()" />
<br />
<hr />
<br />
<div id="Loading" style="display: none">
<table style="width: 200px; height: 200px">
<tr>
<td align="center" valign="middle">
<img id="Img1" src="Images/ajax-loader.gif" alt="loading..." />
</td>
</tr>
</table>
</div>
<div id="Target">
</div>
</div>
</form>
</body>
Tenemos un ScripManager configurado para tener acceso a nuestro código JavaScript:
<Scripts>
<asp:ScriptReference Path="Default.js" />
</Scripts>
y también le configuramos el path a nuestro WebService para que pueda crear automáticamente el proxy que vamos a usar desde nuestro código JavaScript:
<Services>
<asp:ServiceReference Path="PageLoader.asmx" />
</Services>
También tenemos 2 HTML Buttons, uno para llamar a Page1.aspx y otro para Page2.aspx y además 2 divs, uno para mostrar la imagen de Loading mientras se carga la página interior y otro para cargar el HTML que devuelve el WebService.
Al presionar cualquiera de los botones se hace una llamada al AJAX Enabled WebService como vemos en el siguiente código:
function btnLoadPage1_onclick()
{
ret = PageLoader.LoadPage("Page1.aspx", OnComplete, OnTimeOut, OnError);
document.getElementById('Loading').style.display = 'block';
return(true);
}
function btnLoadPage2_onclick()
{
ret = PageLoader.LoadPage("Page2.aspx", OnComplete, OnTimeOut, OnError);
document.getElementById('Loading').style.display = 'block';
return(true);
}
function OnComplete(args)
{
document.getElementById('Target').innerHTML = args;
}
function OnTimeOut(args)
{
alert("Service call timed out.");
}
function OnError(args)
{
alert("Error calling service method.");
}
PageLoader es el proxy creado por el ScriptManager y LoadPage es el [WebMethod] expuesto por nuestro WebService. La llamada es asíncrona por lo que nos pide que especifiquemos la función que se va a llamar cuando se haya completado la petición, la función que se llama si se produce un time out y la función que se llama si se produce un error.
O sea que las funciones de los botones hacen 2 cosas: la petición y mostrar la imagen de Loading.Una vez que el AJAX Enabled WebService devuelve el HTML, cargamos este dentro del div "Target" en la función OnComplete.
Lo que queda ahora es ocultar el Loading, esto lo hacemos desde la página interior, por ejemplo, Page1.aspx, en el evento onload en el body:
<body onload="parent.document.getElementById('Loading').style.display='none';" style="margin:0px;">
<form id="form1" runat="server">
<table style="width:200px;height:200px;">
<tr>
<td valign="middle" align="center" style="background-color:Blue;color:White">
Page1.aspx
</td>
</tr>
</table>
</form>
</body>
Solo quedaría ver el WebService, que lo que hace basicamente es devolver un HTML con un IFRAME con la página que le pasamos como parámetro, de esta forma si nuestra Page1.aspx o Page2.aspx hacen un PostBack, este no afecta a la página contenedora.
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class PageLoader : WebService
{
[WebMethod]
public string LoadPage(string pageName)
{
return @"<iframe frameborder='0'
scrolling='no'
marginheight='0'
marginwidth='0'
height='200px'
width='200px' id='frame' src='" + pageName + "' runat='server'></iframe>";
}
}
Es importante destacar la siguiente línea que es la que permite que el hacer AJAX Enabled al WebService:
[System.Web.Script.Services.ScriptService]
El siguiente gif animado muestra el ejemplo funcionando: