Desarrollando

en tu idioma

Escrito por: TiraCodigo
Etiquetas: MVC, Tutorial, Visual Studio

Hemos llegado al punto donde veremos algo que es muy usual en una aplicación que se diga que tiene buena velocidad, y esto son las llamadas asíncronas con Ajax, que como sabras, se utilizan para refrescar la información de una cierta parte de la página, esto para no tener que cargarla completamente y hacer así el proceso mas rápido y óptimo

Por ejemplo, en el ejemplo anterior donde creamos un contador de palabras, el cual podrás ver aqui, veras que cuando se hace el submit al dar click en el botón, la pagina realiza una redirección completa, es decir se carga toda la página, esto lo podemos optimizar, para que no se cargue toda la pagina, solo una sección, por ejemplo la parte que muestra el resultado de la contabilización, es decir la columna derecha, lo cual podremos realizar de la siguiente manera

En un principio, ocupamos el BeginForm, en donde este contemplaba las dos columnas, la del cuadro donde capturamos el texto, y la columna que muestra la cantidad de palabras:

@using (Html.BeginForm("Index", "Home", FormMethod.Post))
{
    <div style="overflow:hidden">
    <div style="width:600px; float:left">
        <p class="lead">Ingresa un texto</p>
        <p>@Html.TextAreaFor(m => m.Texto, new { style = "width: 400px !important; height: 150px;" })</p>
        <p><input type="submit" class="btn btn-primary btn-lg" value="Contabilizar" /></p>        
    </div>
        <div style="width:400px; float:right">
            <p>Total de palabras = @Model.TotalPalabras </p>
            <p>Densidad de palabras:</p>
            @if (Model.DensidadPalabras !=null && Model.DensidadPalabras.Any()) {
                foreach (var item in Model.DensidadPalabras)
                {
                    <p style="text-indent: 3em">"@item.Palabra" - @item.Cantidad repedita(s)</p>
                }
            }
        </div>
    </div>
}

Lo que ahora aremos, sera utilizar la función Ajax.BeginForm, ya que esta función nos permitirá realizar llamadas asíncronas, así no tendremos la necesidad de recargar toda la pagina, si no la parte que nos interesa, pero antes de poderla utilizar deberemos de cargar la referencia, lo cual realizaremos de la siguiente manera:

- Para agregar la referencia, primero debemos abrir NuGet, esto lo hacemos dando click secundario en el nombre del proyecto

 - En la ventana que salga, buscar "jquery unobtrusive ajax", seleccionar el paquete que marca la captura y dar click en instalar

- Una vez instalado, veras los siguientes scripts:

Para poder utilizar la referencia del script anterior, primero tenemos que modificar el archivo Bundles, y ahi cargar el script de "jquery.unobtrusive-ajax.js" el cual nos debería de quedar así:

using System.Web;
using System.Web.Optimization;

namespace ContadorPalabras
{
    public class BundleConfig
    {
        // For more information on bundling, visit https://go.microsoft.com/fwlink/?LinkId=301862
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
                        "~/Scripts/jquery-{version}.js"));

            bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
                        "~/Scripts/jquery.validate*"));

            bundles.Add(new ScriptBundle("~/bundles/ajax").Include(
                       "~/Scripts/jquery.unobtrusive-ajax.js"));

            // Utilice la versión de desarrollo de Modernizr para desarrollar y obtener información. De este modo, estará
            // ready for production, use the build tool at https://modernizr.com to pick only the tests you need.
            bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
                        "~/Scripts/modernizr-*"));

            bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
                      "~/Scripts/bootstrap.js",
                      "~/Scripts/respond.js"));           

            bundles.Add(new StyleBundle("~/Content/css").Include(
                      "~/Content/bootstrap.css",
                      "~/Content/site.css"));
        }
    }
}

Ya que esta en el Bundles, necesitamos agregar la referencia en la vista del layout, esto en la ultima parte de la vista, casi al final, como se muestra a continuación:

 

...
   
@Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @Scripts.Render("~/bundles/ajax")
    @RenderSection("scripts", required: false)

</body>

</html>

Ahora ya tenemos todo listo para utilizarlo, entonces lo que realizaremos, sera cambiar el Html.BeginForm por Ajax.BeginForm, al utilizar esta función, debemos especificar mas parámetros, entre ellos, el mas importante es definir el div a actualizar, ya que esta, es la única parte de la página que se refrescara y así no cargara toda la página, en nuestro caso, al div de la segunda columna, lo llamamos divResultado

Para que solo se cargue, esa unica parte, pasaremos esa parte de la vista a una Partial View, que es una vista parcial, esto para que cuando se renderise, solo se renderise esta parte, esto lo realizamos creando una nueva vista en la misma carpeta donde esta el index, la cual nombramos como "Resultado", esta nueva vista tendrá este contenido:

@model ContadorPalabras.Models.MiModelo

<p>Total de palabras = @Model.TotalPalabras </p>
<p>Densidad de palabras:</p>
@if (Model.DensidadPalabras != null && Model.DensidadPalabras.Any())
{
                foreach (var item in Model.DensidadPalabras)
    {
        <p style="text-indent: 3em">"@item.Palabra" - @item.Cantidad repedita(s)</p>
    }

}

Teniendo la vista parcial anterior, ahora solo tenemos que realizar la modificacion de nuestra vista Index, para que cargue la vista parcial, y esto lo aremos con la función Html.Partial, donde en los parámetros especificaremos la vista parcial a cargar así como el modelo que va a utilizar como se muestra a continuación:

@model ContadorPalabras.Models.MiModelo

@{
    ViewBag.Title = "Home Page";
}


<div class="jumbotron">
    <div style="overflow:hidden">
@using (Ajax.BeginForm("Index", "Home", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "divResultado" }))
{
    <div style="width:600px; float:left">
        <p class="lead">Ingresa un texto</p>
        <p>@Html.TextAreaFor(m => m.Texto, new { style = "width: 400px !important; height: 150px;" })</p>
        <p><input type="submit" class="btn btn-primary btn-lg" value="Contabilizar" /></p>        
    </div>
}
    <div id="divResultado" style="width:400px; float:right">
            @Html.Partial("Resultado",Model)
    </div>

</div>
</div>

 

Solo nos resta, modificar el controller, para que, al hacer la funcion de POST solo devuelva la vista parcial y no toda la pagina, para esto tendremos que cambiar el return View() por el return PartialView(), quedando como se muestra:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ContadorPalabras.Models;
using System.Linq;

namespace ContadorPalabras.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            var modelo = new MiModelo();
            modelo.TotalPalabras = 0;
            modelo.DensidadPalabras = new List<Densidad>();          

            return View(modelo);
        }

        [HttpPost]
        public ActionResult Index(MiModelo modelo)
        {
            var palabras = new List<string>();
            if (!string.IsNullOrEmpty(modelo.Texto))
            {
                var Delimitador= new List<char>();
                Delimitador.Add(' ');
                Delimitador.Add(',');
                Delimitador.Add('\n');
                palabras = modelo.Texto.Split(Delimitador.ToArray()).ToList();                
                modelo.TotalPalabras = palabras.Count();
                var query = palabras.GroupBy(c => c.ToString()).Select(grupo => new Densidad
                {
                    Palabra = grupo.Key,
                    Cantidad = grupo.Count()
                }).OrderByDescending(x => x.Cantidad);
                modelo.DensidadPalabras = query.ToList();
            }

            return PartialView("Resultado",modelo);
        }
    }
}

Como pudiste ver, el uso es bastante simple, sin embargo se gana mucho en cuestión de optimización realizando pequeños cambios, a continuación te dejo los links para que bajes el proyecto a si como la url para ver corriendo la página

Ver la pagina en ejecución

Descargar el código fuente del ejemplo