Aplicación web móvil con jQuery Mobile y ASP.NET MVC 2 – parte 2

En nuestra aplicación se estará implementando la misma funcionalidad que tiene ya implementado el ejemplo en versión web (navegador de escritorio) que consiste en gestión de clientes, autos y ventas.

Por lo tanto para nuestro ejemplo lo que haremos será copiar el código ya incluido en los controladores y pasarlo a los nuevos controladores que se agregarán al área m los cuales devolverán las vistas para móvil, haremos esto con el fin de ir agarrando práctica para desarrollar con jQuery mobile y asp.net mvc 2; posteriormente podría implementarse todo el proyecto sin áreas ni demás controladores, sino que en las mismas acciones de los controladores que ya tenemos, solo devolver las vistas para móvil simplemente detectando el tipo de navegador del usuario.

Gestión de Clientes (mClientesController)

Agregaremos un nuevo controlador llamado mClientes (si dejamos el nombre solo como Clientes entraría en conflicto con el ya existente.)

Al controlador mClientes agregaremos los using correspondientes (como el using Agencia2012.Models), crearemos la instancia del EntityModel y en la acción Index() escribiremos el código que devolverá la lista de clientes (toda la lista) obteniéndola desde la BD.

using Agencia2012.Models;

namespace Agencia2012.Areas.m.Controllers
{
    public class mClientesController : Controller
    {
        Agencia2012Entities BD = new Agencia2012Entities();

        //
        // GET: /m/mClientes/
        public ActionResult Index()
        {
            //Devolver la vista con la lista de clientes
            return View(BD.Cliente.ToList());
        }

    }
}

Vista Index.

Crear la vista para la acción Index, esta debe ser tipada de la clase Cliente con contenido List y como página maestra Movil.Master (recordar que se comentó en la primera parte).

Img. 1. Añadiendo la vista Index para mClientes.

Agregada la vista, modificaremos el código generado y escribiremos el código para la estructura de página jQuery Mobile en la cual deberá mostrarse la lista de clientes recibida en el modelo.

El código de la vista Index queda como:

<%@ Page Title="" Language="C#" MasterPageFile="~/Areas/m/Views/Shared/Movil.Master" 
        Inherits="System.Web.Mvc.ViewPage<IEnumerable<Agencia2012.Models.Cliente>>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Clientes
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
        <div data-role="page" data-theme="b"  id="clientes">
            <div data-role="header" data-theme="b">
                <a href="/m/inicio" data-icon="home" data-iconpos="notext" rel="external">Inicio</a>
                <h1>Clientes</h1>
                <a href="/m/mclientes/nuevo" data-icon="plus" rel="external">Agregar</a>
            </div>
            <div data-role="content">
            <ul data-role="listview" data-inset="true"  data-theme="c" data-filter="true">
                <%
                    //Crearemos los elementos de la lista
                    //1 elemento = 1 cliente
                    //Para cada cliente se creará un link para poder ver todos sus datos.
                    foreach (var item in Model) { %>
                    <li><%: Html.ActionLink(item.Nombre + " " + item.Apellidos, "vercliente", "mclientes", 
                            new { id=item.IdCliente }, null)%></li>          
                <% } %>
            </ul>
            </div>
            <div data-role="footer" data-theme="a">
                <h4><a href="http://www.afelipelc.mx" rel="external">www.afelipelc.mx</a></h4>
             </div>
        </div>
</asp:Content>

Ejecutando nuestra app y al ingresar a http://localhost:1877/m/mclientes vemos que efectivamente tenemos nuestra lista de clientes (los ya incluidos en la BD) y podemos empezar a probar ya con el botón inicio y después ir a Clientes.

Img. 2. Lista de clientes.

La vista VerCliente

Cuando el usuario de clic sobre el nombre de algún cliente, debemos mostrarle todos los datos, para ello al controlador mClientesController agregaremos una nueva ActionResult llamada VerCliente que reciba como parámetro el id del cliente a visualizar.

public ActionResult VerCliente(int id)
{
    //recuperar el objeto cliente correspondiente al ID
    var cliente = BD.Cliente.Where(c => c.IdCliente == id).FirstOrDefault();
    //si es diferente de nulo, devolver la vista y el objeto cliente
    //sino, solo devolver la vista Error
    if (cliente != null)
    {
        return View(cliente);
    }
    else
        return View("Error");
}

Nota: En esta acción en el caso de no encontrarse el cliente con el ID, devolverá una vista llamada Error, para esto en la carpeta Areas/m/Shared (donde se agregó Movil.Master) debe agregarse la vista Error.aspx (no tipada), la cual su código es:

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Error
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <div data-role="page" data-theme="b"  id="clientes">
    <div data-role="header">
        <a href="/m/inicio" data-icon="arrow-l">Inicio</a>
        <h1>Error</h1>
    </div>
    <div data-role="content">
    <p>Ocurrió un error al procesar la solicitud.</p>
    </div>
    <div data-role="footer" data-theme="a">
        <h4><a href="http://www.afelipelc.mx" rel="external">www.afelipelc.mx</a></h4>
        </div>
    </div>
</asp:Content>

Ya creada la vista Error, ahora crearemos la vista para la acción VerCliente:

Img. 3. Agregar vista VerCliente.

Nuevamente crearemos la estructura de página jQuery Mobile:

<%@ Page Title="" Language="C#" MasterPageFile="~/Areas/m/Views/Shared/Movil.Master" 
    Inherits="System.Web.Mvc.ViewPage<Agencia2012.Models.Cliente>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Ver Cliente
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
        <div data-role="page" data-theme="b"  id="vercliente">
            <div data-role="header" data-theme="b">
                <a data-rel="back" data-icon="arrow-l">Regresar</a>
                <h1>Detalles</h1>
                <a href="/m/mclientes/nuevo" data-icon="plus" rel="external">Agregar</a>
            </div>
            <div data-role="content">
        <div><strong>Nombre:</strong></div>
        <div><%: Model.Nombre + " " + Model.Apellidos%></div>
        <div><strong>Edad:</strong></div>
        <div><%: Model.Edad %></div>
        <div><strong>Calle:</strong></div>
        <div><%: Model.Calle %></div>
        <div><strong>Número:</strong></div>
        <div><%: Model.Numero %></div>
        <div><strong>Localidad:</strong></div>
        <div><%: Model.Localidad.Nombre %></div>
        <div><strong>Municipio:</strong></div>
        <div><%: Model.Localidad.Municipio.Nombre %></div>
        <div><strong>Estado:</strong></div>
        <div><%: Model.Localidad.Municipio.Estado.Nombre %></div>
        <div><strong>Teléfono:</strong></div>
        <div><a href="tel:<%: Model.Telefono %>"><%: Model.Telefono %></a></div>
        <div><strong>Email:</strong></div>
        <div><a href="mailto:<%: Model.Email %>"><%: Model.Email %></a></div>
        <a href="/m/mclientes/editar/<%: Model.IdCliente %>" data-role="button" data-inline="true" rel="external">Editar</a>       
        </div>
            <div data-role="footer" data-theme="a">
                <h4><a href="http://www.afelipelc.mx" rel="external">www.afelipelc.mx</a></h4>
             </div>
        </div>
</asp:Content>

Volvemos a ejecutar la app y nuevamente ingresamos a Clientes y seleccionamos un cliente para ver sus detalles.

Img. 4. Detalles del cliente.

Ahora si damos clic en Regresar vemos que todo va quedando bien.

La vista Editar.

Lo que procede ahora es hacer que cuando el usuario de click sobre “Editar” se le muestre la ventana lista para editar los datos del cliente.

Además debemos considerar que al Editar o Agregar un nuevo cliente, deben validarse los datos antes de proceder a guardarlos, para esto agregaremos un css, algunos scripts y Editor templates.

En la carpeta Areas/m/Content agregar una nueva carpeta llamada CSS, y dentro de esta agregar un nuevo elemento “Hoja de estilos” llamado estilos.css tal y como se muestra en la imagen.

Img. 5. Agregar nueva hoja de estilos.

Como contenido del archivo estilos.css agregaremos solamente un estilo.

label.obligatorio  {
	color:#FF0000;
	font-weight:bold;
}

Ahora agregaremos un nuevo archivo de JavaScript (nuevo elemento Archivo JScript) a la carpeta Areas/m/scripts llamado clientevars.js en el que declararemos todas las variables a utilizar en nuestro validador.

Img. 6. Agregar nuevo archivo de JavaScript.

El contenido del archivo clientevars.js solo tendrá las declaraciones de variables que se utilizarán para realizar la validación del formulario y cuadro de diálogo.

// Declaración de variables globales - deben hacerce antes de $(document).ready()
var hdrMainvar = null;
var contentMainVar = null;
var ftrMainVar = null;
var contentTransitionVar = null;
var estadolblVar = null;
var municipiolblvar = null;
var localidadlblvar = null;
var estadoVar = null;
var municipioVar = null;
var localidadVar = null;
var formvar = null;
var contentDialogVar = null;
var contentConfirmationVar = null;
var inputMapVar = null;

// constantes
var MISSING = "obligatorio";
var EMPTY = "";
var noselect = "0";

Script que realizará la función de validar el formulario.

En la carpeta scripts (igual que clientevars.js) agregar un nuevo archivo llamado clientevalidador.js cuyo contenido será la función validar al momento de enviar el formulario y otras funciones más, su código queda como:

//archivo clientevalidador.js

$(document).ready(function () {
    // asignar valores a variables globales
    hdrMainVar = $('#hdrMain');
    contentMainVar = $('#contentMain');
    ftrMainVar = $('#ftrMain');
    contentTransitionVar = $('#contentTransition');
    estadolblVar = $('#estadolbl');
    municipiolblvar = $('#municipiolbl');
    localidadlblvar = $('#localidadlbl');
    estadoVar = $('#IdEstado');
    municipioVar = $('#IdMunicipio');
    localidadVar = $('#IdLocalidad');
    formVar = $('#datoscliente');
    contentDialogVar = $('#contentDialog');
    inputMapVar = $('.obligatorio');
    hideContentDialog();
});

$('#buttonOK').click(function () {
    hideContentDialog();
    showMain();
    return false;
});

$('#datoscliente').submit(function () {
    var err = false;
    // Oculatar el contenido de la página
    hideMain();

    // Quitar las clases que posiblemente se agregaron al
    //realizar una validación previa
    estadolblVar.removeClass(MISSING);
    municipiolblvar.removeClass(MISSING);
    localidadlblvar.removeClass(MISSING);
    inputMapVar.each(function (index) {
        $(this).prev().removeClass(MISSING);
    });

    // Verificar todos los campos marcados con la class="obligatorio"
    inputMapVar.each(function (index) {
        if ($(this).val() == null || $(this).val() == EMPTY) {
            $(this).prev().addClass(MISSING);
            err = true;
        }
    });

    //validar el combo Estado
    if (estadoVar.val() == noselect) {
        estadolblVar.addClass(MISSING);
        err = true;
    }
    //validar el combo Municipio
    if (municipioVar.val() == noselect) {
        municipiolblvar.addClass(MISSING);
        err = true;
    }
    //validar el combo Localidad
    if (localidadVar.val() == noselect) {
        localidadlblvar.addClass(MISSING);
        err = true;
    }

    // Si la validación falla, mostrar la ventana de dialogo
    if (err == true) {
        showContentDialog();
        return false;
    }

    // Enviar el formulario
    formVar.submit();
});

function hideMain() {
    hdrMainVar.hide();
    contentMainVar.hide();
    ftrMainVar.hide();
}

function showMain() {
    hdrMainVar.show();
    contentMainVar.show();
    ftrMainVar.show();
}

function hideContentDialog() {
    contentDialogVar.hide();
}

function showContentDialog() {
    contentDialogVar.show();
}

Hace falta el script para manipular los combos, por lo tanto agregar un nuevo Script llamado scriptmunicipios.js a la carpeta scripts (ya tenemos un archivo similar en la carpeta Content/scripts del proyecto).

//archivo scriptmunicipios.js

$("#IdEstado").bind("change", function (event, ui) {
    //obtener el Id del estado
    var idedo = $("#IdEstado").val();

    //limpiar el combo de municipios y localidades
    $("#IdMunicipio").children("option").remove();
    $("#IdLocalidad").children("option").remove();

    //Si el ID del edo seleccionado es diferente de 0, cargar sus mpios
    if (idedo > 0) {

        //crear la URL
        var url = "../../../MunicipiosService/MunicipiosEdo?idedo=" + idedo;
        //hacer la llamada JSON
        $.getJSON(url,
			function (data) {
			    var opcion = "<option value=\"0\">Seleccionar Localidad</option>";
			    $("#IdMunicipio").append(opcion);

			    opcion = "Seleccionar Localidad";
			    $("#IdLocalidad").append(opcion);

			    $.each(data, function (i, item) {
			        //agregar los elementos al combo
			        var opcion = "<option value=\"" + item.Id + "\">" + item.Nombre + "</option>";
			        $("#IdMunicipio").append(opcion);

                    //indicar que se actualize su apariencia en la pág. jQuery Mobile
			        $("#IdMunicipio").selectedIndex = 0;
			        $("#IdMunicipio").selectmenu("refresh");

			        $("#IdLocalidad").selectedIndex = 0;
			        $("#IdLocalidad").selectmenu("refresh");
			    });
			});

    }
});

$("#IdMunicipio").bind("change", function (event, ui) {
    //obtener el Id del estado
    var idmpio = $("#IdMunicipio").val();

    //limpiar el combo de municipios
    $("#IdLocalidad").children("option").remove();

    //Si el ID del edo seleccionado es diferente de 0, cargar sus mpios
    if (idmpio > 0) {

        //cargar con JSON
        var url = "../../../MunicipiosService/LocalidadesMpio?idmpio=" + idmpio;

        //hacer la llamada JSON
        $.getJSON(url,
			function (data) {
			    var opcion = "<option value=\"0\">Seleccionar Localidad</option>";
			    $("#IdLocalidad").append(opcion);
			    $.each(data, function (i, item) {
			        //agregar los elementos al combo
			        var opcion = "<option value=\"" + item.Id + "\">" + item.Nombre + "</option>";
			        $("#IdLocalidad").append(opcion);

			        //indicar que se actualize su apariencia en la pág. jQuery Mobile
			        $("#IdLocalidad").selectedIndex = 0;
			        $("#IdLocalidad").selectmenu("refresh");
			    });
			});
    }
});

Nota: En el archivo scriptmunicipios.js se realizan peticiones Ajax al servidor a la dirección MunicipiosService/MunicipiosEdo?idedo=N_Id, el proyecto incluye ya un controlador llamado MunicipiosServiceController el cual proveé las listas de Municipios y Localidades en formato JSON que es procesada con jQuery y agrega cada elemento a los combos.

Entonces al final tendremos estos archivos juntos:

Img. 7. Archivos JavaScript.

La acción Editar.

Implementaremos ahora la acción Editar (GET y POST) en mClientesController que recibe como parámetro el ID del cliente a modificar.

public ActionResult Editar(int id)
{
    //recuperar el objeto Cliente a editar
    var cliente = BD.Cliente.Where(c => c.IdCliente == id).FirstOrDefault();
    //Si es diferente de null, cargar listas de estados, municipios y
    //localidades donde vive el cliente
    //y posteriormente devolver la vista Editar con todos los datos recuperados.

    //Sino, devolver la vista error.
    if (cliente != null)
    {
        ViewData["Estados"] = Listas.Estados();
        ViewData["Municipios"] = Listas.MunicipiosEstado((int)cliente.Localidad.Municipio.IdEstado);
        ViewData["Localidades"] = Listas.LocalidadesMunicipio((int)cliente.Localidad.IdMunicipio);

        return View(cliente);
    }
    else
        return View("Error");
}

[HttpPost]
public ActionResult Editar(int id, FormCollection datos)
{
    //recuperar el objeto Cliente a actializar.
    var cliente = BD.Cliente.Where(c => c.IdCliente == id).FirstOrDefault();
    try
    {
        //Actualizar el modelo (objeto almacenado) con los datos del formulario.
        UpdateModel(cliente, datos);
        BD.SaveChanges();
        //redireccionarlo a VerDatos.
        return Redirect("../../mclientes/vercliente/" + cliente.IdCliente);
    }
    catch
    {
        return View("Error");
    }
}

Y ahora con la vista Editar, para hacer esto un poco más fácil, crearemos un editor template tipado de la clase Cliente (una vista parcial ascx que se utiliza como plantilla).

La plantilla Cliente.ascx

En Areas/m/Views/mClientes agregaremos una nueva carpeta llamada EditorTemplates.

Img. 8. Agregar carpeta EditorTemplates a Views/mClientes

Dentro de esta nueva carpeta agregaremos la vista parcial Cliente (.ascx).

Img. 9. Agregar vista parcial Cliente.ascx.

Nuestra plantilla tendrá todos los campos del formulario organizados en divs con atributos jQuery Mobile, en los que se incluye también combos adicionales como Estado (IdEstado), Municipio (IdMunicipio) y Localidad (IdLocalidad) de manera que pueda verse más dinámico al seleccionar el lugar de residencia donde estos combos serán procesados con jQuery.Ajax + JSON; el código para esta plantilla es:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Agencia2012.Models.Cliente>" %>
<div id="Div1" data-role="fieldcontain">
    <%: Html.HiddenFor(model => model.IdCliente)%>
    <label for="Nombre">Nombre*</label>
    <%: Html.TextBoxFor(model => model.Nombre, new {@class="obligatorio" })%>
</div>
<div id="Div2" data-role="fieldcontain">
    <label for="Apellidos">Apellidos*</label>
    <%: Html.TextBoxFor(model => model.Apellidos, new { @class = "obligatorio" })%>
</div>
<div id="Div3" data-role="fieldcontain">
    <label for="Edad">Edad*</label>
    <%if (Model != null)
        { %>
    <input type="number" name="Edad" id="Edad" min="18" max="70" pattern="[0-9]*" required="required" value="<%: Model.Edad %>" />
    <%}
        else
        { %>
        <input type="number" name="Edad" id="Edad" min="18" max="70" pattern="[0-9]*" required="required" />
    <%} %>
</div>
<div id="Div4" data-role="fieldcontain">
        <label id="estadolbl" for="Estado">Estado*</label>
        <% if (Model != null && Model.Localidad != null)
            {%>
                <%: Html.DropDownList("IdEstado", new SelectList(ViewData["Estados"] as IEnumerable, "IdEstado", "Nombre", Model.Localidad.Municipio.Estado.IdEstado), new Dictionary<string, object>() { { "data-native-menu", "true" } })%>
            <%
        }
        else
        { %>
            <%: Html.DropDownList("IdEstado", new SelectList(ViewData["Estados"] as IEnumerable, "IdEstado", "Nombre"), new Dictionary<string, object>() { { "data-native-menu", "true" } })%>
        <% } %>
</div>
<div id="Div5" data-role="fieldcontain">
    <label id="municipiolbl" for="Municipio">Municipio*</label>
    <% if (Model != null && Model.Localidad != null)
        {%>
            <%: Html.DropDownList("IdMunicipio", new SelectList(ViewData["Municipios"] as IEnumerable, "IdMunicipio", "Nombre", Model.Localidad.Municipio.IdMunicipio), new Dictionary<string, object>() { { "data-native-menu", "true" } })%>
        <%
    }
    else
    { %>
        <select id="IdMunicipio" name="IdMunicipio" data-native-menu="true"><option value="0">Seleccionar municipio</option>
        </select>
    <% } %>
</div>
<div id="Div6" data-role="fieldcontain">
    <label for="Localidad" id="localidadlbl">Localidad*</label>
    <% if (Model != null && Model.Localidad != null)
    {%>
        <%: Html.DropDownList("IdLocalidad", new SelectList(ViewData["Localidades"] as IEnumerable, "IdLocalidad", "Nombre", Model.IdLocalidad), new Dictionary<string, object>() { { "data-native-menu", "true" } })%>
    <%
    }
    else
    { %>
        <select id="IdLocalidad" name="IdLocalidad" data-native-menu="true"><option value="0">Seleccionar localidad</option>
        </select>
    <% } %>
</div>
<div id="Div7" data-role="fieldcontain">
    <label for="Calle">Calle*</label>
    <%: Html.TextBoxFor(model => model.Calle, new { @class = "obligatorio" })%>
</div>
<div id="Div8" data-role="fieldcontain">
    <label for="Numero">Numero*</label>
    <%: Html.TextBoxFor(model => model.Numero, new { @class = "obligatorio" })%>
</div>
<div id="Div9" data-role="fieldcontain">
    <%: Html.LabelFor(model => model.Telefono)%>
    <%if (Model != null)
        { %>
        <input type="tel" name="Telefono" id="Telefono" value="<%: Model.Telefono %>" />
    <%}
        else
        { %>
        <input type="tel" name="Telefono" id="Telefono"/> 
    <%} %>              
</div>
<div id="Div10" data-role="fieldcontain">
    <%: Html.LabelFor(model => model.Email)%>
    <%if (Model != null)
        { %>
        <input type="email" name="Email" id="Email" value="<%: Model.Email %>" />
    <%}
        else
        { %>
        <input type="email" name="Email" id="Email"/>  
    <%} %>                                               
 </div>

Creando la vista Editar con la plantilla Cliente.ascx Integrada.

Para el ActionResult Editar, crear la vista tipada de la clase Cliente con contenido Edit.

Img. 10. Crear vista Editar.

En esta vista agregaremos la estructura jQuery Mobile y enlazaremos a los archivos css y js creados, el código de la vista Editar queda como:

<%@ Page Title="" Language="C#" MasterPageFile="~/Areas/m/Views/Shared/Movil.Master" 
    Inherits="System.Web.Mvc.ViewPage<Agencia2012.Models.Cliente>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Editar
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    <script src="../../../Areas/m/Content/scripts/clientevars.js" type="text/javascript"></script>
    <link href="../../../Areas/m/Content/css/estilos.css" rel="stylesheet" type="text/css" />
<!-- Inicio de la página -->
<div data-role="page" data-theme="b" id="editarcliente">
<div data-role="header" id="hdrMain" data-theme="b" name="hdrMain" data-nobackbtn="true">
<a href="/m/mclientes" data-icon="arrow-l">Clientes</a>
           <h1>Editar</h1>
        <a href="/m/mclientes/nuevo" data-icon="plus" rel="external">Agregar</a>
</div>
<div data-role="content" id="contentMain" name="contentMain">
        <form id="datoscliente" action="" method="post">
        <!-- Invocar al EditorTemplate Cliente.ascx que es nuestra plantilla -->
         <%: Html.EditorFor(model => Model) %>
            <p>
                <button type="submit" data-theme="b" data-inline="true">Guardar</button> 
                <a data-rel="back" data-role="button" data-theme="d" data-inline="true">Cancelar</a>
            </p>
   </form>
</div><!-- Fin del contenído de la página -->
<div data-role="footer" data-theme="a">
                <h4><a href="http://www.afelipelc.mx" rel="external">www.afelipelc.mx</a></h4>
     </div>
<!-- Contenedor que utilizaremos como cuadro de diálogo al momento de validar -->
  <div align="center" data-role="content" id="contentDialog" name="contentDialog">
<div>Llene todos los campos marcados con * antes de enviar el formulario.</div>
<a id="buttonOK" name="buttonOK" href="#editarcliente" data-role="button" data-inline="true">Aceptar</a>
</div> <!-- fin contenedor de diálogo -->
    <!-- Enlazar a los scripts para que puedan ser ejecutados correctamente -->
    <script src="../../../Areas/m/Content/scripts/clientevalidador.js" type="text/javascript"></script>
    <script src="../../../Areas/m/Content/scripts/scriptmunicipios.js" type="text/javascript"></script>
</div> <!-- fin de toda la página jQuery M -->
</asp:Content>

Ejecutemos nuestra app y ahora si podemos dar clic en “Editar” en detalles del cliente:

Img. 11. Vista Editar Cliente.

Si eliminamos el dato de algún campo y hacemos clic en Guardar, comprobamos que la validación funciona.

Img. 12. Diálogo de notificación.

Al hacer clic en Aceptar, los campos son señalados.

Img. 13. Campos vacíos señalados.

También funcionan los combos.

Img. 14. Comprobación de combos.

Y finalmente hechos los cambios podemos guardarlos y ver el resultado.

Img. 15. Resultado de cambios realizados.

Nota: Es importante que las páginas para Editar y Registrar se carguen como enlaces EXTERNOS con el atributo jQueryM rel=”external” ya que jQuery Mobile carga las páginas con AJAX y de esta forma los Scripts no son cargados por lo que es necesario cargar una página por completo (incluyendo css y scripts).

Hasta aquí se termina esta parte, continuaremos con la parte Registrar la cual solo es crear la vista similar a Editar.

Créditos: La validación de formularios fue tomada de http://mobile.tutsplus.com/tutorials/mobile-web-apps/jquery-mobile-forms/

2 comentarios en “Aplicación web móvil con jQuery Mobile y ASP.NET MVC 2 – parte 2

    1. Los combos de Estado, Municipio y Localidad no funcionan para Editar en la versión web de escritorio porque se me pasó incluir en la vista Editar los script y el script de jQuery.

      En la versión móvil es más probable que no se esté cargando el scriptmunicipios.js porque los que ya terminaron el tutorial les funciona todo al 100.

Escribe tu comentario:

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s