14 Diciembre, 2016 / by fjmenendez / Web / No Comments

ASP.NET MVC renderizado vista vs parciales vs visibilidad por javascript

En este artículo, vamos a hacer una comparativa del “renderizado” o “pintado” de una vista en ASP.NET MVC de tres formas distintas.

  1. La primera es la más básica petición de la vista al controlador.
  2. En una segunda parte veremos cómo dividir la vista en vistas parciales.
  3. Como tercer punto solicitaremos sólo la parte que necesitamos actualizar mediante el uso de vistas parciales.
  4. Y por último, en vez de refrescar la información, pasaremos a obtenerla en la primera petición del “html” y “jugaremos” con la visibilidad.

Como ejemplo intentaremos mostrar tres páginas:

  • Inicio
  • Información
  • Contacto.

Podéis descargar el código en GitHub.

https://github.com/elfranchu/Carga-Vistas-Parciales

Para comenzar, vamos a crear un  nuevo proyecto de ASP.Net MVC

 

Elegimos como plantilla uno que este vacío, para no tener demasiadas distracciones.

Modelos

 

Crearemos los modelos que utiliza el controlador anterior

 

En primer lugar un modelo para el contenido de la página

public class PageContent
{
   public string Title { get; set; }
   
   public string Description { get; set; }
}

 

Así el PageContent, será distinto para cada página.

Crearemos una enumeración que identifique cada página

public enum EnumViewMode
{
   Index,
   Info,
   Contact
}

 

Agregaremos un modelo que englobe la información anterior junto con los elementos comunes a todas las páginas, que podrían ser la “Cabecera” y el “Pie de página”.

public class MyModel
{
  public string Header { get; set; }
  
  public PageContent MainContent { get; set; }
  public string Footer { get; set; }

  public EnumViewMode ViewMode { get; set; }
}

Y un modelo avanzado para el último caso

public class MyModelAllInOne
{
  public string Header { get; set; }
  public PageContent IndexMainContent { get; set; }
  public PageContent InfoMainContent { get; set; }
  public PageContent ContactMainContent { get; set; }
  public string Footer { get; set; }
  public EnumViewMode ViewMode { get; set; }
}

En el que podríamos decir que viajaría toda la información de estas tres páginas.
Agregamos una carpeta “Home” en la carpeta Views y en ella una vista “Index.cshtml”

Como ya sabréis, esta vista  se alimentará de un controlador  HomeController, lo creamos.

public class HomeController : Controller
{
   // GET: /Home/
   public ActionResult Index()
  {  
  }
}

 

La estructura de vistas y controladores debería quedar así:

 

Y la estructura de vistas tal que así

1.- Petición de la vista al controlador.

Para esta parte, usaremos el controlador home, para simplemente atender las peticiones de vista.

Recordemos que queremos el contenido de 3 vistas, Inicio, Información y Contacto, en el controlador devolvemos un modelo lleno para cada vista

public class HomeController : Controller
 {
 //
 // GET: /Home/

 public ActionResult Index()
 {
 MyModel m = new MyModel();
 m.Header = string.Format("Parte de Cabecera Actualizada:{0}", DateTime.Now);
 m.Footer = string.Format("Parte de Pie de Página Actualizada:{0}", DateTime.Now);

 m.MainContent = new PageContent();
 m.MainContent.Title = "Página de Inicio";
 m.MainContent.Description = "Esta es la descripción de la página de Inicio:Lorem . . . .. . .";
 return View(m);
 }

 public ActionResult Info()
 {
 MyModel m = new MyModel();
 m.Header = string.Format("Parte de Cabecera Actualizada:{0}", DateTime.Now);
 m.Footer = string.Format("Parte de Pie de Página Actualizada:{0}", DateTime.Now);

 m.MainContent = new PageContent();
 m.MainContent.Title = "Página de Información";
 m.MainContent.Description = "Esta es la descripción de la página de Información:Lorem ipsum. . . .. . .";
 return View(m);
 }

 public ActionResult Contact()
 {
 MyModel m = new MyModel();
 m.Header = string.Format("Parte de Cabecera Actualizada:{0}", DateTime.Now);
 m.Footer = string.Format("Parte de Pie de Página Actualizada:{0}", DateTime.Now);

 m.MainContent = new PageContent();
 m.MainContent.Title = "Página de Contacto";
 m.MainContent.Description = "Esta es la descripción de la página de Contacto:Lorem ipsum dol. . . .. . .";

 return View(m);
 }
 
 }

 

Y en la vista, construimos el html, a partir del modelo devuelto por el controlador con sintaxis razor.

@model DynamicPartialLoad.Models.MyModel
@{
 ViewBag.Title = "Index";
}
@Html.Partial("_menu")
<h2>@Model.Header</h2>
<h2>Pagina de inicio</h2>
<div>
 <p>Estos datos vienen del controlador, a través del modelo:</p>
 <h2>Title: @Model.MainContent.Title</h2>
 <p>Description: @Model.MainContent.Description</p>
</div>

2.- Dividir la vista en parciales.

Vemos que las peticiones de las tres vistas tienen en común la cabecera y el pie de página, o lo que es lo mismo, discrepan en la parte central.
Pues bien crearemos una vista parcial para cada vista anterior y transformaremos la vista para que “pinte” estas parciales

<div id="contenidocentral">

 @if (Model.ViewMode == EnumViewMode.Index)
 {
 @Html.Partial("_partialIndex", Model.MainContent)
 }
 else if (Model.ViewMode == EnumViewMode.Contact)
 {
 @Html.Partial("_partialContact", Model.MainContent)
 }
 else if (Model.ViewMode == EnumViewMode.Info)
 {
 @Html.Partial("__partialInfo", Model.MainContent)
 }
 </div>

El controlador devuelve en el modelo el contenido de la vista parcial

public class UsarParcialesController : Controller
{
public ActionResult Index(string id)
{
MyModel m = new MyModel();
m.Header = string.Format("Parte de Cabecera Actualizada:{0}", DateTime.Now);
m.Footer = string.Format("Parte de Pie de Página Actualizada:{0}", DateTime.Now);
if (id == "Info")
{
  m.MainContent = new PageContent()
 {
  Title = "Página de Información",
  Description = "Esta es la descripción de la página de VER CÓDIGO COMPLETO EN GitHub"
 };
}

/*Ver código completo*/

return View(m);

}

 

3.-Cargar sólo la parte a actualizar

Además de que el controlador devuelva en el modelo el contenido de la vista parcial, hay ocasiones en las que no sería necesario pedir toda la página sino que se puede realizar una petición de página parcial.

Por ejemplo, si estamos en la página de “información” y queremos ver la página de “contacto”, y dado que estas comparten la cabecera y el pie de página, lo único que necesitamos actualizar es el contenido central.

Así, siguiendo con el ejemplo anterior, nos encontramos en la página de “información”, y tenemos un link que nos lleva a la página de “contacto”

<div>
   <a class="contactlink" href="/CargarParciales/CenterAsPartial/Contact">Contacto</a>
</div>

 

Con JQuery, capturamos el evento click de este link

$(".contactlink").click(function (e) {

// se ha producido un click en el link

e.preventDefault();

});

Y cargamos  la vista parcial en la parte central en concreto en la capa cuyo id es “contenidocentral”.

$(document).ready(function () {

function LoadPartial(obj) {

//Cargar la url de la parcial

var url = $(obj).attr('href')

console.debug(url);

$("#contenidocentral").load(url);

}

 

$(".contactlink").click(function (e) {

LoadPartial(this);

e.preventDefault();

});

Al ejecutar la función load, se hace una petición al controlador que no devuelve el html de la  página, sino la parte de la parcial, con este html se reemplaza el contenido de la capa “contenidocentral” .

public ActionResult CenterAsPartial(string id)
{
PageContent m = new PageContent();
if (id == "Contact")
{
m = new PageContent();
{
Title = "Página de Contacto",
Description = "Esta es la descripción de la página de Contacto:………….."
};

return PartialView("_partialContact", m);

}

}

 

4.- Obtención en una simple petición

Por último, en vez de refrescar la información, pasaremos a obtenerla en la primera petición del “html” y “jugaremos” con la visibilidad. Esta forma aunque no muy ortodoxa tiene claras ventajas para páginas pequeñas, normalmente alojadas en servidores compartidos y donde una cada petición tarda bastante.

Con una sola petición se podría tener todo el html, eso sí sería más grande.

Necesitamos un nuevo modelo para desarrollar esta parte

public class MyModelAllInOne
{
public string Header { get; set; }

public PageContent IndexMainContent { get; set; }

public PageContent InfoMainContent { get; set; }

public PageContent ContactMainContent { get; set; }

public string Footer { get; set; }

public EnumViewMode ViewMode { get; set; }

}

Como hemos dicho, en una sola petición debe ir nuestro sitio completo, por eso este modelo lleva una “cabecera” y un “pie”, que son comunes a todas las páginas y tres contenidos “Inicio”, “Información” y “Contacto”.

 

Nuestro código para la vista sería:

@Html.Partial("_menu")

<h2>@Model.Header</h2>

<div id="indexdiv">

 

<h2>Pagina de Inicio con parcial</h2>

<div>

<span>Contenido Actualizado: @DateTime.Now.ToString()</span>

<br>

<p>Estos datos vienen del controlador, a través del modelo:</p>

<h2>Title: @Model.IndexMainContent.Title</h2>

<p>Description: @Model.IndexMainContent.Description</p>

</div>

</div>

<div id="infodiv">

 

<h2>Pagina de Información con parcial</h2>

<div>

<span>Contenido Actualizado: @DateTime.Now.ToString()</span>

<br>

<p>Estos datos vienen del controlador, a través del modelo:</p>

<h2>Title: @Model.InfoMainContent.Title</h2>

<p>Description: @Model.InfoMainContent.Description</p>

</div>

</div>

<div id="contactdiv">

 

<h2>Pagina de Contacto con parcial</h2>

<div>

<span>Contenido Actualizado: @DateTime.Now.ToString()</span>

<br>

<p>Estos datos vienen del controlador, a través del modelo:</p>

<h2>Title: @Model.ContactMainContent.Title</h2>

<p>Description: @Model.ContactMainContent.Description</p>

</div>

</div>

 

<h2>@Model.Footer</h2>

 

A destacar tres capas en donde irán pintadas cada parcial “indexdiv”, “infodiv” y

“contactdiv”.

Como sólo queremos que se vea una, modificaremos su visibilidad dinámicamente con JQuery® en función de la url.

 

if (window.location.href.endsWith("AllInOne/Index") == false)

$("#indexdiv").hide();

if (window.location.href.endsWith("AllInOne/Info") == false)

$("#infodiv").hide();

if (window.location.href.endsWith("AllInOne/Contact") == false)

$("#contactdiv").hide();

 

Como en  el ejemplo anterior, estamos en la página de “información” y queremos ver la página de “contacto”

<div>

<a class="contactlinkjquery" href="/AllInOne/Contact">Contacto</a>    </div>

Con JQuery, capturamos el evento click de este link, y modificamos la visibilidad de las capas, dependiendo de los parámetros de la url.

Modificamos además el historial de Html5, para permitir el refresco de página

$(".contactlinkjquery").click(function (e) {

ShowPartial(this);

e.preventDefault();

});




function ShowPartial(obj) {

var url = $(obj).attr('href')

// Ocultamos todas las capas

$("#indexdiv").hide();

$("#infodiv").hide();

$("#contactdiv").hide();




if (url.indexOf('/Index') > 0) {

$("#indexdiv").show();

history.pushState(null, "Inicio", "Index");

}

if (url.indexOf('/Contact') > 0) {

$("#contactdiv").show();

history.pushState(null, "Contacto", "Contact");

}

if (url.indexOf('/Info') > 0) {

$("#infodiv").show();

history.pushState(null, "Info", "Info");

}

}

 

Bueno, menuda parrafada.

Espero haberos introducido múltiples dudas sobre el mundo de las parciales, y que comentéis

Gracias

“El ignorante afirma; el sabio duda y reflexiona.”,  Aristóteles

 

 

 

Deja un comentario

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