Mostrando entradas con la etiqueta jQuery. Mostrar todas las entradas
Mostrando entradas con la etiqueta jQuery. Mostrar todas las entradas

viernes, 29 de junio de 2012

[ASP.NET] PopUp Edición - Usando Jquery UI Dialog

 

Introducción


En este ejemplo se editaran ordenes de compra pero sin hacer uso alguno de eventos de asp.net, se hará uso de una serie de librerías jquery que ayudaran en el proceso

Solo el botón de filtro y la paginación del gridview conservarán los eventos de asp.net, la edición de la entidad será completamente sin hacer uso de eventos.

Para esto se usara:

  • jquery UI dialog
  • jquery autocomplete
  • jtemplates
  • momentjs

Implementando jQuery Autocomplete


La implementación se encuentra en el archivo autocomplete.js del proyecto, en este simplemente se define

$(function () {

    $("[id*='txtCustomer']").autocomplete({

        source: function (request, response) {

            var params = new Object();
            params.companyName = request.term;

            $.ajax({
                type: "POST",
                contentType: "application/json; charset=utf-8",
                url: "Default.aspx/GetCustomerList",
                data: JSON.stringify(params),
                dataType: "json",
                async: true,
                success: function (data) {

                    response($.map(data.d, function (item) {
                        return {
                            label: item
                        }
                    }))
                },
                error: function (request, status, error) {
                    alert(jQuery.parseJSON(request.responseText).Message);
                }
            });

        },

        open: function (event, ui) {

            $(this).autocomplete("widget").css({
                "width": 200, "font-size": 12
            });

        },

        select: function (event, ui) {

            $("[id*='txtCustomer']").val(ui.item.label);

        }


    });
});

 

Como puede observarse invoca a un WebMethod implementado en el código de la pagina

[WebMethod]
public static string[] GetCustomerList(string companyName)
{
    string[] list = CustomerRepository.GetCustomer(companyName)
                            .Select(x => x.CompanyName)
                            .ToArray();

     return list;
}

Es importante resaltar el uso de una sección de estilo que permite definir el scroll del desplegable

<style type="text/css">
    .ui-autocomplete {
	    max-height: 200px;
	    overflow-y: auto;
	    /* prevent horizontal scrollbar */
	    overflow-x: hidden;
	    /* add padding to account for vertical scrollbar */
	    padding-right: 20px;
    }
</style>

Implementando Edición GridView


La edición en el control GridView tiene algunos detalles interesantes para el análisis. la selección se implementa por medio de un simple template conteniendo el tag de html de imagen al cual se le asocia un atributo para identificar el id de la orden que define

Este atributo será luego usado por el evento de la imagen cuando hace $(this).attr(“idorder”)

function RegisterEditOrderEvent() {

    $("[id*='gvOrders'] [id*='imgeditorder']").click(function () {

        var orderId = $(this).attr("idorder");

        $('#popuporderedit').dialog({ title: 'Edicion Orden Nro: ' + orderId });
        $('#popuporderedit').data('orderId', orderId);
        $('#popuporderedit').dialog('open');

    });

}

Nota: hay que remarcar como se asigna el id de la orden al dialogo, usando el .data(), usado luego para saber que id esta mostrando el popup

Se observara también que este evento no esta en el clásico $(function(){… para que se cargue cuando la pagina este disponible, sino que es invocado puntualmente ante determinados eventos.

Esto es necesario porque el gridview sigue conservando los eventos de asp.net, y el postback que estos causando quitan las asociaciones de los eventos de jquery adjunta a los controles, a pesar de usar UpdatePanel estos eventos aun existen, por eso se usa al final de cada acción el ScriptManager.RegisterStartupScript() para que vuelva a lanzar la ejecución y rebindear el evento click

protected void gvOrders_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
    gvOrders.PageIndex = e.NewPageIndex;
    LoadGridOrder();

    ScriptManager.RegisterStartupScript(Page, typeof(Page), "registerorderevent", "RegisterEditOrderEvent();", true);

}

protected void btnFiltrar_Click(object sender, EventArgs e)
{
    LoadGridOrder();

    ScriptManager.RegisterStartupScript(Page, typeof(Page), "registerorderevent", "RegisterEditOrderEvent();", true);
}

Edición usando jQuery UI Dialog


La definición es bastante simple, lo que quizás sea complejo es la carga y actualización de los campos de la entidad

$('#popuporderedit').dialog({
    autoOpen: false,
    modal: true,
    resizable: false,
    width: 500,
    heigth: 250,
    title: 'Edicion Orden Nro:',
    open: function (event, ui) {

        initialize();
        loadOrder($(this).data('orderId'));

    },
    close: function (event, ui) {

        //limpia todos los textbox del popup
        $('#popuporderedit :text').val('');

    },
    buttons: {
        Actualizar: function () {

            updateOrder();

        },
        Cancel: function () {
            $(this).dialog("close");
        }
    }
});

Jquery UI Dialog – Carga controles


La carga de los datos en el popup tiene dos momentos, una de inicialización y otra de asignación de los datos de la entidad que se edita

En este caso la inicialización mas que nada implica cargar los combo

function initialize() {

    loadComboBox('ddlCustomer', 'GetAllCustomer');
    loadComboBox('ddlEmployeer', 'GetAllEmploye');
    loadComboBox('ddlShipVia', 'GetAllShipper');
    
}

function loadComboBox(comboname, webmethodname) {

    var template = "{#foreach $T as record}\
                        <option value='{$T.record.id}'>{$T.record.name}</option>\
                    {#/for}";

    var combo = $('#' + comboname);

    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: "Default.aspx/" + webmethodname,
        data: '{}',
        dataType: "json",
        async: true,
        success: function (data) {

            //combo.setTemplate($("#SelectTemplate").html());
            combo.setTemplate(template);
            combo.processTemplate(JSON.parse(data.d));
           
        },
        error: function (request, status, error) {
            alert(JSON.parse(request.responseText).Message);
        }
    });

}

Es importante notar como se hace uso de jtemplate para definir el <option> de combo. El témplate puede ser definido tanto en una variable, o si este es algo mas complejo podría hacerse en una sección del html

<script type="text/html" id="SelectTemplate">
    {#foreach $T as record}
        <option value="{$T.record.id}">{$T.record.name;}</option>
    {#/for}
</script>

Para que se puede recuperar la info será necesario contar con los webmethod

[WebMethod]
public static string GetAllCustomer()
{
    var list = CustomerRepository.GetAllCustomer()
                            .Select(x => new 
                            {
                                id = x.CustomerID,
                                name = x.CompanyName
                            });

    return JsonConvert.SerializeObject(list);
}

[WebMethod]
public static string GetAllEmploye()
{
    var list = EmployeRepository.GetAllEmploye()
                            .Select(x => new
                            {
                                id = x.EmployeeID,
                                name = x.FullName
                            });

    return JsonConvert.SerializeObject(list);
}

[WebMethod]
public static string GetAllShipper()
{
    var list = ShipperRepository.GetAllShipper()
                            .Select(x => new
                            {
                                id = x.ShipperID,
                                name = x.CompanyName
                            });

    return JsonConvert.SerializeObject(list);
}

Se hace uso de la librería JSON.Net para serializar el objeto anónimo

Para cargar la orden se usa una técnica similar

function loadOrder(orderId) {

    var params = new Object();
    params.orderId = orderId;

    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: "Default.aspx/GetOrder",
        data: JSON.stringify(params),
        dataType: "json",
        async: true,
        success: function (data) {

            var order = JSON.parse(data.d);

            $('#ddlCustomer').val(order.CustomerID);
            $('#ddlEmployeer').val(order.EmployeeID);

            $('#txtOrderDate').val(order.OrderDate);
            $('#txtRequiredDate').val(order.RequiredDate);
            $('#txtShippedDate').val(order.ShippedDate);

            $('#ddlShipVia').val(order.ShipVia);
            $('#txtFreight').val(order.Freight);
            $('#txtShipName').val(order.ShipName);
            $('#txtShipAddress').val(order.ShipAddress);
            $('#txtShipCity').val(order.ShipCity);
            $('#txtShipRegion').val(order.ShipRegion);
            $('#txtShipPostalCode').val(order.ShipPostalCode);
            $('#txtShipCountry').val(order.ShipCountry);


        },
        error: function (request, status, error) {
            alert(JSON.parse(request.responseText).Message);
        }
    });


}

Definiendo el webmethod que envía los datos de la orden

[WebMethod]
public static string GetOrder(int orderId)
{
    var order = OrderRepository.GetOrderById(orderId);

    return JsonConvert.SerializeObject(new
    {
        OrderID = order.OrderID,
        CustomerID = order.CustomerID,
        EmployeeID = order.EmployeeID,

        OrderDate = order.OrderDate.ToShortDateString(),
        RequiredDate = order.RequiredDate.ToShortDateString(),
        ShippedDate = order.ShippedDate.HasValue ? order.ShippedDate.Value.ToShortDateString() : "",

        ShipVia = order.ShipVia,

        Freight = order.Freight,
        ShipName = order.ShipName,
        ShipAddress = order.ShipAddress,
        ShipCity = order.ShipCity,
        ShipRegion = order.ShipRegion,
        ShipPostalCode = order.ShipPostalCode,
        ShipCountry = order.ShipCountry
    }); 

}

Fue necesario redefinir la entidad que se envía y no directo la entidad Order ya que de no hacerse se obtiene un error de referencia circular, causado por las entidades asociadas en Entity Framework

 

Jquery UI Dialog – Actualización


Actualizar la entidad implica crear un objeto javascript que represente la entidad, lo bueno es que JSON.stringify() lo hace muy fácil, mapeando la entidad directamente

function updateOrder() {

    var order = new Object();
    order.OrderID = $('#popuporderedit').data('orderId');

    order.CustomerID = $('#ddlCustomer').val();
    order.EmployeeID = $('#ddlEmployeer').val();

    order.OrderDate = moment($('#txtOrderDate').val(), "DD/MM/YYYY").toDate();
    order.RequiredDate = moment($('#txtRequiredDate').val(), "DD/MM/YYYY").toDate();

    var shippedDate = moment($('#txtShippedDate').val(), "DD/MM/YYYY");
    order.ShippedDate = shippedDate == null ? null : shippedDate.toDate(); 

    order.ShipVia = $('#ddlShipVia').val();
    order.Freight = $('#txtFreight').val();
    order.ShipName = $('#txtShipName').val();
    order.ShipAddress = $('#txtShipAddress').val();
    order.ShipCity = $('#txtShipCity').val();
    order.ShipRegion = $('#txtShipRegion').val();
    order.ShipPostalCode = $('#txtShipPostalCode').val();
    order.ShipCountry = $('#txtShipCountry').val();

    var params = new Object();
    params.order = order;

    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: "Default.aspx/ActualizarOrder",
        data: JSON.stringify(params),
        dataType: "json",
        async: true,
        success: function (data) {

            alert('Actualizacion Correcta');
            $('#popuporderedit').dialog("close");

        },
        error: function (request, status, error) {
            alert(JSON.parse(request.responseText).Message);
        }
    });


}

El único inconveniente fue con las fechas, al encontrarse en formato dd/MM/yyyy esta no era reconocida por javascript, es por eso que con ayuda de momentjs se logro cambiar de formato a una fecha correcta

 

Código


Para el ejemplo se hace uso de Visual Studio 21010, la base de datos es Sql Compract 3.5

 

[C#]
 

martes, 29 de mayo de 2012

[ASP.NET] - GridView sumar columnas con jquery

 

Introducción

Cuando se trabaja integrando código cliente (javascript) con asp.net seguramente en algún punto se necesite realizar operaciones con tablas, siendo el control GridView  usado en la mayoría de estos casos, es por eso se intentara mostrar las diferentes formas en que se puede realizar operaciones con código cliente usando jquery para trabajar con tablas

Para el ejemplo se listara productos con sus respectivos precios, el usuario completara la cantidad que se solicita de ese producto, realizando el calculo del precio final que deberá abonarse.

 

Calculo del precio por producto

La primer operación que debe programarse corresponde al calculo a nivel de fila, o sea de cada producto. La implementación completa podrá verse en el código dentro de al carpeta “Ej1”.

Como se observa en la imagen la columna del precio unitario es fija, el usuario ingresa una cantidad y al quitar el foco del textbox automáticamente se calcula el precio.

Para lograrlo será necesario adjuntar un evento de cambio a cada textbox del gridview, recordemos que el control termina renderizado como una tabla html, por lo tanto, se puede trabajar en el cliente con el html resultante.

<script language="javascript" type="text/javascript">

    $(document).ready(function() {

        $("#<%=GridView1.ClientID%> [id*='txtCantidad']").change(function() {
        
            var tr = $(this).parent().parent();
            var precio = $("td:eq(1)", tr).html();

            $("td:eq(3) span", tr).html($(this).val() * precio);

        });

    });
    
</script>

Ante un evento se recupera el textbox que lanza la acción, es por eso que se utiliza $(this), el this en este caso es el textbox, se sube dos niveles en la estructura del html, o sea a nivel del <tr> que contiene a ese textbox, para luego aplicar la selección a otra columna, en este caso la del precio, por eso se utiliza td:eq(1) seria la segunda columna (recordar que los índices comienzan en cero)

El ultimo paso será asignar el resultado, se aplica la misma técnica, se selecciona la columna y por tratarse de un label de asp.net el cual renderiza a <span> se usa este selector en jquery.

Si bien en la implementación puede observarse solo una única forma para asignar el evento a los textbox contenido en la columna de gridview pueden ser usados otro selectores de jquery dependiendo la necesitad:

 

Usando el atributo class

En este caso el selector hace uso de un atributo del control para poder localizarlo, todos los textbox que el gridview genere tendrán el mismo atributo “class”

$('#<%=GridView1.ClientID%> .cantidad').change(function() { ….

Es necesario definir este atributo en el control del témplate del grid

Usando un doble selector

En este caso se aplicara una doble selección, primero se selecciona lo definido a la derecha y sobre esto aplica lo definido en al izquierda.

$('td:eq(2) :text', '#<%=GridView1.ClientID%> tr').change(function() {

La parte derecha selecciona todas las filas del grid, mientras que la izquierda toma solo la tercer columna (Cantidad Pedido), el uso de “:text” define que solo los textbox de la celda serán incluidos

 

Usando el operador like *=

Por medio del operador de selección mediante búsqueda aproximada, se puede tomar todos aquellos controles que tengan un misma patrón en su id

$("#<%=GridView1.ClientID%> [id*='txtCantidad']").change(function() {

En el caso del gridview creara un control por cada dato que se le asigne, repitiendo el textbox N veces, pero todos tendrán la palabra txtCantidad en alguna parte de su id

 

Calculo del precio Total

Calcular el precio total, implica sumar una columna completa para tener el precio total que se sumara en el footer del gridview. La implementación completa podrá verse en el código dentro de al carpeta “Ej2”.

El añadido que se realiza a la suma de la fila del grid solo implica la llamada a una funciona para recalcular el total.

Un punto conflictivo cuando se suma una columna es el hecho de paginar la grid, vamos a ver en este caso como se lograría una implementación con y sin paginado

 

Calculo total sin paginado

Al no paginar se puede reconocer el footer como ultima fila de la tabla pudiendo aplicar selectores que tengan en cuenta esta situación.

function CalcularTotal() {

    var total = 0;
    $('#<%=GridView1.ClientID%> tr:not(:last)').each(function() {
    
        var coltotal = parseFloat($("td:eq(3) span", this).html());
        
        if (!isNaN(coltotal)) {
            total += coltotal;
        }

    });

    $('#<%=GridView1.ClientID%> tr:last td:eq(3) span').html(total);
}

Se puede hacer uso de “:last” para agregar o descartar esta ultima fila del grid donde se presentara el total.

Se recorre todas las filas del gridview, dejando fuera el footer, por eso es “:not(:last)”, se esta descartando el ultimo <tr>. Pero si se toma exactamente la ultima fila cuando se quiere asignar el total resultante, por eso se usa el “tr:last”

Nota: por supuesto hay que quitar la propiedad AllowPaging="True" del gridview para probarlo sin paginado

 

Calculo total con paginado

Al tener paginado la ultima final ya no será el footer, por lo tanto usar el :last no funciona, se requiere otras técnicas de selección

function CalcularTotal() {

    var total = 0;
    $("#<%=GridView1.ClientID%> [id*='lblPrecio']").each(function() {

        var coltotal = parseFloat($(this).html());

        if (!isNaN(coltotal)) {
            total += coltotal;
        }

    });

    $("#<%=GridView1.ClientID%> [id*='lblTotal']").html(total);

}

 

Se decide ir directamente a los controles que contienen la información.

Al tomar el valor del <span> (que representa el lblPrecio), puede que este no sea un valor numérico valido, es por eso que se parsea a float, si devuelve NaN es porque no es un numero que sumar.

 

Código

Se ha usado Visual Studio 2008, es necesario SP1 del VS, como base de datos Sql Compact 3.5

 

martes, 20 de marzo de 2012

jqGrid–Crear jerarquía de registros con Tree Grid

 

Introducción

La finalidad buscada con el articulo articulo será demostrar como por medio del componente jqGrid se pueden representar estructuras de árbol en diferentes niveles de agrupación

El ejmeplo esta basado en la ordenes de compra de la db Northwind, tomando el campo “OrderData” y agrupando por año y mes

Es por eso que la opciones de expandir primero mostrarán los años, luego los mese y al final la info de la orden.

Se puede dejar el campo de Customer sin ingresar un valor, lo cual listara todas las ordenes registradas

Es muy importante notar en el código como se crea el grid que se enviara por json al grid

var grid = new
{
    page = 1,
    records = orderList.Count,
    total = orderList.Count,

    rows = from item in orderList
            select new
            {
                id = item.IdUnique,
                cell = new string[]
                {
                    item.Id,
                    item.Desc,
                    item.Level.ToString(),
                         item.Parent,
                         item.IsLeaf.ToString().ToLower(),
                        "false"
                }
            }

 

};

luego de los campos de datos se debe definir en orden los siguiente ítems:

  • nivel
  • parent
  • si es un nodo hoja
  • si debe mostrarse expandido el nodo

 

Código


El ejemplo esta confeccionado con VS 2010 y Sql Compact (la db se encuentra en la carpeta App_Data)

[C#]
[C# Skydrive]

domingo, 27 de noviembre de 2011

jqGrid – Listar Orden Compra (Maestro-Detalle)

 

Introducción

La mayoría de las veces los controles que incluye una herramienta de desarrollo puedo no cumplir con las expectativas que uno busca si quiere alcanzar una interfaz rica que aproveche toda la potencia de desarrollo, es por eso que se debe recurrir a componentes externos.

Esta situación suelo encontrarla al mostrar información en un grid, es por eso que jqGrid es un control ideal para potenciar el desarrollo de la interfaz del usuario en entorno web y además se trata de un componente de libre uso.

Lo único aspecto a tener en cuenta se relaciona con la necesidad de conocer algo de javascript, concretamente jquery y de ser posible invocación a webmethods para recuperar la información del grid.

image

 

Configuración

Para poder hacer uso de jqGrid es necesario introducir en el proyecto algunas librerías de javascript.

Las cuales pueden ser descargadas de la pagina jqGrid

La referencia a estas librerías podrían hacerse de dos formas:

- usando el tag <script> en cada una de las paginas donde se requiera el grid

<script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
<script src="Scripts/jquery-ui-1.8.16.custom.min.js" type="text/javascript"></script> 

<script src="Scripts/jqGrid/grid.locale-es.js" type="text/javascript"></script>
<script src="Scripts/jqGrid/jquery.jqGrid.min.js" type="text/javascript"></script>
<link href="Scripts/jqGrid/ui.jqgrid.css" rel="stylesheet" type="text/css" />

- o usando ScriptManager.RegisterClientScriptInclude(), esto es útil cuando se quiere registrar librerías para todas las paginas de forma global, aplicándolo en el código de la Master Page

public partial class SiteMaster : System.Web.UI.MasterPage
{
    protected override void OnInit(EventArgs e)
    {

        ScriptManager.RegisterClientScriptInclude(Page, typeof(Page), "jquery", ResolveUrl(@"~/Scripts/jquery-1.6.4.min.js"));
        ScriptManager.RegisterClientScriptInclude(Page, typeof(Page), "jqueryui", ResolveUrl(@"~/Scripts/jquery-ui-1.8.16.custom.min.js"));
        ScriptManager.RegisterClientScriptInclude(Page, typeof(Page), "json2", ResolveUrl(@"~/Scripts/json2.js"));
        
        ScriptManager.RegisterClientScriptInclude(Page, typeof(Page), "gridlocale", ResolveUrl(@"~/Scripts/jqGrid/grid.locale-es.js"));
        ScriptManager.RegisterClientScriptInclude(Page, typeof(Page), "jqgrid", ResolveUrl(@"~/Scripts/jqGrid/jquery.jqGrid.min.js"));

        base.OnInit(e);
    }

}

Al usarse un Master Page este podría verse afectado por la rutas relativas de las paginas, lo que ocasionaría una incorrecta resolución de la url y el acceso a los archivos .js, el método ResolveUrl() nos ayuda a evitar este problema.

 

Definición del grid

Definir el grid con las opciones básicas no es nada difícil, para separar el código de scripting del html de la pagina facilitando así el mantenimiento verán en el ejemplo que he definido 3 .js según la operación de cada uno

En este caso en concreto, se usara el “Grid.js”, el cual define el grid maestro

$("#tbOrders").jqGrid({
    datatype: 'json',
    colNames: ['Fecha Pedido', 'Fecha Solicitud', 'Direccion', 'Ciudad', 'Pais'],
    colModel: [
             { name: 'OrderDate', index: 'OrderDate', width: 100, sortable: false },
             { name: 'RequiredDate', index: 'RequiredDate', width: 100, sortable: false },
             { name: 'ShipAddress', index: 'ShipAddress', width: 250, sortable: false },
             { name: 'ShipCity', index: 'ShipCity', width: 110, sortable: false },
             { name: 'ShipCountry', index: 'ShipCountry', width: 110, sortable: false }
              ],
    height: "300px",
    onSelectRow: function (id) {

        getDetailsOrderByOrder(id);

    }
});

y un grid detalle

$("#tbDetailsOrder").jqGrid({
    datatype: 'json',
    colNames: ['Producto', 'Cantidad', 'Precio'],
    colModel: [
             { name: 'ProductName', index: 'ProductName', width: 250, sortable: false },
             { name: 'Quantity', index: 'RequiredDate', width: 100, sortable: false },
             { name: 'UnitPrice', index: 'UnitPrice', width: 100, sortable: false }
              ],
    height: "200px",
    width:"800px"
});

La configuración es bastante estándar para un uso básico, a partir de aquí hay miles de opciones, pero básicamente se define las columnas (atributo “colNames”), así como también las propiedades de cada columnas como ser el ancho de las mismas.

En el grid maestro además se define un evento, el cual enviara el id de la entidad seleccionada para cargar así el detalle, por supuesto el id que recibe como parámetro es el valor que mas adelante veremos en la estructura json devuelta por el webmethod

 

Definición de los Page Métodos

El siguiente paso será definir la información en el servidor para poder recuperar los registros que cargaran el grid

Para esto se define dos Page Methods en la propia pagina web que implementa los grid (podría usarse una pagina adicional para esta definición)

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static string GetOrdersByCustomer(string customer)
{

    var orders = NorthwindData.GetOrdersByCustomer(customer);

    var grid = new
    {
        page = 1,
        records = orders.Count(),
        total = orders.Count(),

        rows = from item in orders
               let orderdate = item.OrderDate.HasValue ? item.OrderDate.Value.ToShortDateString() : ""
               let requireddate = item.RequiredDate.HasValue ? item.RequiredDate.Value.ToShortDateString() : ""
              
               select new
               {
                   id = item.OrderID,
                   cell = new string[]{
                       orderdate,
                       requireddate,
                       item.ShipAddress,
                       item.ShipCity,
                       item.ShipCountry,
                       item.Customers.CompanyName

                   }
               }

    };

    return JsonConvert.SerializeObject(grid);
}

 

la estructura que requiere jqGrid es un tanto especial, y gracias a los métodos anónimos es posible armarla, y como ultimo paso serializarla usando la librería JSON.NET

La estructura es bastante simple, se define la pagina, la cantidad de registros y el total, estos valores son útiles cuando el grid esta paginado, en este caso no implementamos la paginación.

Luego se definen las filas, en donde se transforma la entidad obteniendo un identidicado en el “id”, mas una propiedad “cell” que es en definitiva un array de string con la información de cada columna requiere, es importante en este punto respetar las posiciones en que debe ir cada dato con respecto a las definición de las columnas en el paso anterior.

El mismo proceso se aplica para recuperar los detalles

[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static string GetDetailsOrdersByOrder(int order)
{

    var orders = NorthwindData.GetDetailsOrdersByOrder(order);

    var grid = new
    {
        page = 1,
        records = orders.Count(),
        total = orders.Count(),

        rows = from item in orders
               select new
               {
                   id = item.OrderID,
                   cell = new string[]{
                       item.ProductsReference.Value.ProductName,
                       item.Quantity.ToString(),
                       item.UnitPrice.ToString("N2")
                   }
               }

    };

    return JsonConvert.SerializeObject(grid);
}

 

Invocar a los Page Methods

Los grid definidos no están conectados de forma directa para que estos invoquen los servicios de datos, sino que se definieron por separado para que uno desde código controle la invocación de los servicios.

En el archivos ServiceInvoke.js se encuentra la definición

function getOrdersByCustomer(customer) {

    var params = new Object();
    params.customer = customer;

    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: "Default.aspx/GetOrdersByCustomer",
        data: JSON.stringify(params),
        dataType: "json",
        async: false,
        success: function (data, textStatus) {

            if (textStatus == "success") {

                $("#tbDetailsOrder").clearGridData();

                var grid = $("#tbOrders")[0];
                grid.addJSONData(jQuery.parseJSON(data.d));

            }

        },
        error: function (request, status, error) {
            alert(jQuery.parseJSON(request.responseText).Message);
        }
    });

}

 

Por medio de la línea

$("#tbDetailsOrder").clearGridData();

es que se limpian los registros del grid de detalle, ya que al recargarse el principal ya no hay un registro seleccionado.

function getDetailsOrderByOrder(order) {

    var params = new Object();
    params.order = order;

    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        url: "Default.aspx/GetDetailsOrdersByOrder",
        data: JSON.stringify(params),
        dataType: "json",
        async: false,
        success: function (data, textStatus) {

            if (textStatus == "success") {

                var grid = $("#tbDetailsOrder")[0];
                grid.addJSONData(jQuery.parseJSON(data.d));

            }

        },
        error: function (request, status, error) {
            alert(jQuery.parseJSON(request.responseText).Message);
        }
    });

}

 

Ejemplo de Código


El ejemplo fue desarrollado con visual Studio 2008 y Sql Server 2008 R2 Express

Dentro de la carpeta “DbScript” se encuentra un .sql con la estructura de la db en caso de no poder usar el .mdf adjunto en la solución

 

[C#] 
 

domingo, 8 de mayo de 2011

[jQuery] RadioButton y CheckBox

 

Introducción

Después del artículo donde se analizo la forma de trabajar con controles de lista como ser los combos y listbox

[jQuery] Trabajo con ListBox y Combos

seguiremos con otro grupo de controles igual de importantes: Radio Buttons y Checkbox.

Listado de temas

  1. RadioButton
    1. Recuperar ítem Seleccionado
    2. Asignar Selección
    3. RadioButtonList
  2. CheckBox
    1. Recuperar ítem Seleccionado
    2. Asignar Selección
    3. CheckBoxList

 

1- RadioButton

1.1 – Recuperar ítem Seleccionado

En las siguientes líneas se observara algunas de las formas posibles en que se puede recuperar el ítem seleccionado en un radio button.

 

function btnEj1SeleccionUsandoClass_OnClick() {

    var valor = $('.Ej1radio:checked').val()

    $('#Ej1Resultado').html(valor);
}

function btnEj1SeleccionUsandoName_OnClick() {

    var valor = $("input[name='Ej1radio']:checked").val()

    $('#Ej1Resultado').html(valor);
}

function btnEj1SeleccionUsandoTabla_OnClick() {

    var valor = $("#Ej1Table :radio:checked").val()

    $('#Ej1Resultado').html(valor);
}

Básicamente en todas se hace uso del selector :checked para tomar los radio marcados por el usuario, al saber que solo uno puede seleccionarse, se recupera el valor mediante el método val()

1- se usa una clase asignada a los distintos radio button, por el uso del punto, este es el selector de clase de jquery

2- se selecciona por medio de atributo name, todos los radio deben tener el mismo

3- se selecciona la tabla que contiene los controles , luego los radio (mediante :radio), hay que mencionar que si en la misma tabla existe otro grupo de radio button este tipo de selección no podría ser aplicado, porque tomaría todos los radio sin discriminar cada agrupación

1.2 – Asignar selección

La asignación de un valor especifico a los radio se reduce a cambiar el atributo checked.

function btnEj2SeleccionarConTabla_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    $("#Ej2Table :radio[value='" + valor + "']").attr('checked', true);

}


function btnEj2SeleccionarPorName_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;
        
    $(":radio[name='Ej2radio'][value='" + valor + "']").attr('checked', true);

}

En ambos caso se asigna el atributo “checked” a true para que este se desmarque, como los radio trabajaban en grupo no hace falta desmarcar al resto, ya que esto se hace automáticamente.

1- se selecciona la tabla que contiene el radio y se usa como filtro el valor ingresado en el textbox

2- se usa el nombre que define al grupo de radio buttons, luego sobre estos filtrar por el valor

También existen otras formas de seleccionar un ítem:

function btnEj2SeleccionarAtributoJavascript_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    var option = $(":radio[name='Ej2radio'][value='" + valor + "']");

    if (option.length > 0)
        option[0].checked = true;

}

function btnEj2SeleccionarConForEach_OnClick() {
    
    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    $.each($("#Ej2Table :radio"), function() {

        if (this.value == valor) {
            this.checked = true;
        }

    });

}

1- se busca el option que coincide, pero la acción de checkear se logra por medio de la propiedad provista por javascript. El usar el ítem cero [0], no es porque la selección devuelve varios resultados en la búsqueda en un array, sino que se esta tomando el control javascript de la selección de jquery.

2- aquí la búsqueda se realiza mediante un loop por todos los radio, comparando su valor con el buscado, el que coincida será marcado

1.3 – RadioButtonList

En esta sección se hará uso de control propuesto por asp.net para representar un conjunto de radios.

Si se analiza con el “IE Developer Tools”, al cual se accede presionado F12, se podrá inspeccionar el html generado por el control de lista de radio buttons

Como se observa la opción esta compuesta por el input común de html, pero la descripción esta dentro de un label

function btnEj3SeleccionUsandoName_OnClick() {

    var option = $(":radio[name='rdlEj3']:checked");
    var texto = $('label', option.parent());

    var msg = 'texto: {0}, valor: {1}'.format(texto.html(), option.val());

    $('#Ej3Resultado').html(msg);
}

Es por eso que luego de tomar la option seleccionado se usa el parent() para subir un nivel, ahora estaremos posicionado en el tag <td>, y dentro de este se recupera el label, de esta forma se obtendrá la descripción del option marcado.

Algo interesante aquí es que en la línea

$('label', option.parent())

se esta usando un selector de un selector, o sea se buscara solo el label que este dentro de ese tag <td> y no en todo el sitio, es por eso que se separa por coma, a la izquierda iría la selección del ámbito donde aplica el selector de la derecha.

2- CheckBox

2.1 - Recuperar ítem Seleccionado

En la selección del checkbox se necesita algo mas de código, ya que pueden ser varios los ítems marcados.

En todos los ejemplos se recorren los checks elegidos y se vuelca a una array para mostrar el resultado en pantalla, aquí se aplica la misma técnica que en el artículo previo, cuando se analizo el ListBox.

function btnEj1SeleccionUsandoClass_OnClick() {

    var list = new Array();

    $.each($('.Ej1check:checked'), function() {

        var msg = 'valor: {0}'.format($(this).val());
        list.push(msg);

    });

    $('#Ej1Resultado').html(list.join('
'));
}

function btnEj1SeleccionUsandoName_OnClick() {
    
    var list = new Array();

    $.each($("input[name='Ej1check']:checked"), function() {

        var msg = 'valor: {0}'.format($(this).val());
        list.push(msg);

    });

    $('#Ej1Resultado').html(list.join('
'));
    
}

function btnEj1SeleccionUsandoTabla_OnClick() {

    var list = new Array();

    $.each($("#Ej1Table :checkbox:checked"), function() {

        var msg = 'valor: {0}'.format($(this).val());
        list.push(msg);

    });

    $('#Ej1Resultado').html(list.join('
'));
    
}

1- se hace uso de la clase asignada a los ckeck para determinar cuales fueron marcados, al igual que los radio se usa el punto de jquery como selector

2- el mismo nombre es usado en cada check que forma parte del grupo, este es usando este como selector, el name es un atributo por eso es que se define entre []

3- se selecciona la tabla que contiene los checks, recorriendo los seleccionados

2.2 - Asignar Selección

Aquí también hay varias formas de lograrlo al igual que los radio, pero a diferencia del control anterior si es necesario un paso previo que limpie la selección previa, es por eso que se hace uso del metodo attr() que asigna el atributo checked en false

$("#Ej2Table :checkbox").attr('checked', false);

puede variar la forma en que se aplica la selección de jquery, pero la idea es obtener todos los checks y de un golpe desmarcarlos.

En estos ejemplo se puede ingresar en el TextBox varios valores separados por coma, es por eso que se recorre cada numero ingresado para tomar el check que mapea con este valor y marcarlo. Se logra este objetivo por medio del $.each y el split() de la cadena de valores ingresados.

 

function btnEj2SeleccionarConTabla_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    $("#Ej2Table :checkbox").attr('checked', false);
    
    $.each(valor.split(','), function() {
    
        $("#Ej2Table :checkbox[value='" + this + "']").attr('checked', true);

    });

}


function btnEj2SeleccionarPorName_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    $(":checkbox[name='Ej2check']").attr('checked', false);

    $.each(valor.split(','), function() {

        $(":checkbox[name='Ej2check'][value='" + this + "']").attr('checked', true);

    });

}

1- se hace uso de la tabla para tomar los check que están contenidos

2- se recuperan los check por el atributo name asignado al grupo

 

function btnEj2SeleccionarAtributoJavascript_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    $(":checkbox[name='Ej2check']").attr('checked', false);

    $.each(valor.split(','), function() {

        var option = $(":checkbox[name='Ej2check'][value='" + this + "']");
        
        if (option.length > 0)
            option[0].checked = true;
    });

}

3- se hace uso de la propiedad checked de javascript para marcar el control, aquí la selección recupera el check concreto, pero luego con el uso de [0] se toma el control puro en javasscript que contiene esa propiedad checked

Remarco que la propiedad checked no es parte de jquery, este usa el attr() para cambiar el valor, solo javascript posee esta propiedad, por eso el uso del [0] en el resultado del selector de jquery

 

function btnEj2SeleccionarConForEach_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;
    
    $(":checkbox[name='Ej2check']").attr('checked', false);
    
    
    $.each($("#Ej2Table :checkbox"), function() {

        var check = this;
        
        $.each(valor.split(','), function() {

            if (check.value == this)
                check.checked = true;

        });

    });

}

4- se aplica la misma técnica del punto 3, pero se realiza un doblo loop, primero por cada check en la tabla y luego por los valores ingresados. No digo que esta sea la forma mas optima de implementarlo, pero me pareció interesante mostrarlo para conocer como unir dos ciclos.

 

function btnEj2SeleccionarUniendoValores_OnClick() {

    var valor = $('#txtEj2').val();

    if (valor == null)
        return;

    $(":checkbox[name='Ej2check']").attr('checked', false);

    var valuesList = Array();

    $.each(valor.split(','), function() {

        var value = "[value='{0}']".format(this);
        valuesList.push(value);

    });

    $(":checkbox[name='Ej2check']").filter(valuesList.join(',')).attr('checked', true);

}

5- esta ultima técnica de selección es bastante particular ya que arma un array de filtros que es ejecutado mediante el método filter() de jquery sobre la selección de todos los checks. Es necesario marcar que cada ítem del filtro deberá ser separado por comas.

2.3- CheckBoxList

Al igual que con el RadioButtonList, es una buena idea inspeccionar el html resultante del render

Algo interesante que se puede observar es que el control rendiza una tabla de nombre “rdlEj3” que podría ser usada para seleccionar los check contenidos en esta.

function btnEj3SeleccionUsandoName_OnClick() {
   
    var options = $("#rdlEj3 :checkbox:checked");

    var list = new Array();

    $.each(options, function() {

        var option = $(this);
        var valor = $(this).parent().attr('hiddenValue');
        var texto = $('label', option.parent());

        var msg = 'texto: {0}, valor: {1}'.format(texto.html(), valor);
        list.push(msg);

    });

    $('#Ej3Resultado').html(list.join('
'));
}

En este caso se toma los check dentro de la tabla que asp.net crea para contener estos controles, tomando de esta solo los tildados.

Algo que debe marcarse es que el CheckBoxList no ingresa el valor de cada ítem, es por eso que en el código .net en el evento Page_Load cuando se asignan los ítems, se pusieron unas líneas que agregan el valor del ítem

foreach (ListItem item in rdlEj3.Items)
{
    item.Attributes["hiddenValue"] = item.Value; 
}

Esto se rendizan en el html dentro de un tag <span>, es por eso que en las líneas 9 al 11 se hace uso del parent() para subir un elemento al seleccionado y recuperar esta información.

El control base que provee asp.net solo crea el atributo value=”on” como puede verse en la imagen, el atributo “hiddenValue” es creado al en el loop de cada ítem luego de cargar la lista.

 

Ejemplo de código

 

viernes, 29 de abril de 2011

[jQuery] Trabajo con ListBox y Combos

 

Introducción

Este artículo se pretende continuar lo empezado en:

[jQuery] Por donde comenzar

En esta ocasión trataremos un conjunto diferente de controles, estos muy usados en un desarrollo web.

En este caso particular trataremos controles de lista: ListBox y Combos. Notando cuan similares son a la hora de trabajarlos.

Selección de Ítems

En los ejemplos indicados como 1 y 2, se recuperan los ítems marcados por parte del usuario, pudiendo manipularlos y trabajar con la información.

 

        function btnEj1Seleccion_OnClick() {

            var list = new Array();

            $.each($('#Ej1Select :selected'), function() {
               
                var msg = 'texto: {0}, valor: {1} 
'.format($(this).text(), $(this).val());
                list.push(msg);

            });

            $('#Ej1Resultado').html(list.join(''));
            
        }

        function btnEj2Seleccion_OnClick() {
           
            var optionSelected = $('#Ej2Select :selected');

            var msg = 'texto: {0}, valor: {1}'.format(optionSelected.text(), optionSelected.val());

            $('#Ej2Resultado').html(msg);

        }

Los selectores usados en ambos casos son idénticos, solo lo diferencia la selección múltiple que puede brindar un ListBox, es por eso que aplica un loop por cada ítem marcado por el usuario.

En este código hay que marcar algunos puntos de interés:

La función $.each() recorre la selección de una lista de ítems y aplica una función por cada uno de ellos.

En este caso en concreto se recorre cada ítem seleccionado de la lista, o sea se obtiene cada <option> tomando de este el valor y el texto. Es importante notar que esta función tiene acceso a cada ítem por medio del this, pero se trata de un objeto javascript y no jquery, es por eso que se aplica nuevamente un selector $(this), para tener acceso a los métodos que permiten acceder recuperar la información.

Con respecto al selector, este accede al control por medio del sus id, por eso el uso del #, pero de este se filtra además los seleccionados usando el :selected.

Por fuera de la función se crea un array de javascript para ubicar cada dato marcado, se inserta el texto resultante de cada item por medio de push(), y al final se lo une por medio del join(), para lograr un solo string.

Seguramente se habrá notado además el uso del una función format() para reemplazar en el texto ciertas posiciones con un dato en concreto, bien esta función en si no es estándar de javascript, sino que se encuentra definida en utils.js, y básicamente aplicaría como un método de extensión para los tipos de datos string.

El trabajo con combos es idéntico a la lista, pero solo se toma un ítem accediendo de forma directa, no requiere ser recorrido sus ítems, por eso es algo más simple aplicar los selectores.

 

Agregar / Remover Ítems

La sección marcada para el Ejemplo 3, representa la operación de agregar y remover elementos en una lista.

        function btnEj3Agregar_OnClick() {

            var ej3Texto = $('#txtEj3Texto');
            var ej3Valor = $('#txtEj3Valor');

            var newItem = $('<option/>').text(ej3Texto.val()).val(ej3Valor.val());
            $("#Ej3Select").append(newItem);

        }
        
        function btnEj3AgregarDespuesSeleccion_OnClick() {

            var itemsSelected = $('#Ej3Select :selected');

            if (itemsSelected.length == 0) {
                alert('Debe seleccionar un item');
                return;
            }
                
            var ej3Texto = $('#txtEj3Texto');
            var ej3Valor = $('#txtEj3Valor');

            var newItem = $('<option/>').text(ej3Texto.val()).val(ej3Valor.val());
            newItem.insertAfter(itemsSelected[0]);

        }
        

        function btnEj3Seleccion_OnClick() {
        
            var list = new Array();

            $.each($('#Ej3Select :selected'), function() {

                var msg = 'texto: {0}, valor: {1} 
'.format($(this).text(), $(this).val());
                list.push(msg);

            });

            $('#Ej3Resultado').html(list.join(''));
            
        }

        function btnEj3RemoverSeleccion_OnClick() {

            $.each($('#Ej3Select :selected'), function() {

                $(this).remove();

            });
        }

El agregar una nueva opción requiere que el html de <opción> sea creado, es por eso que se define este en el selector, para luego disponer de método de text() y val() para asignar la información proveniente del input del usuario.

Una vez creado el nuevo ítem solo se hace un append() a la lista existente, también se podrían usar métodos como ser insertBefore() o insertAfter() para controlar la ubicación del nuevo elemento, pero esto requiere que se indique que elemento será tomado como objetivo. En el ejemplo al hacer uso de estos métodos se debe asegurar que al menos un ítem esta marcado para que funcione correctamente, si mas de uno se ha seleccionado solo se toma el primero.

El remover un ítem es muy simple, solo se recorre la selección y se aplica el remove(), al igual que en la selección, el this representa cada ítem en el loop, aquí también es necesario aplicar nuevamente el selector para tener acceso a los método de jquery implementa.

Trabajar con combos es idéntico a las listas, solo que se opera con un solo ítem a la vez, el ejemplo 4 implementa justamente estas acciones en un combo:

function btnEj4Agregar_OnClick() {

    var ej4Texto = $('#txtEj4Texto');
    var ej4Valor = $('#txtEj4Valor');

    var newItem = $('<option/>').text(ej4Texto.val()).val(ej4Valor.val());
    $("#Ej4Select").append(newItem);

}

function btnEj4Seleccion_OnClick() {

    var optionSelected = $('#Ej4Select :selected');

    var msg = 'texto: {0}, valor: {1}'.format(optionSelected.text(), optionSelected.val());

    $('#Ej4Resultado').html(msg);

}

function btnEj4RemoverSeleccion_OnClick() {

    $('#Ej4Select :selected').remove()

}

Algo que quizás no he marcado en los otros ejemplos es que al utilizar algo como esto

var optionSelected = $('#Ej4Select :selected');

se debe comprender que se esta asignado a la variable la selección del objeto completo, es por eso que luego se puede acceder a la funcionalidad provista por jquery.

 

Asignar Selección

En algún momento seguramente se requiera marcar un valor de la lista o combo sin que el usuario realice la acción, sino que será por medio de código, por suerte jquery hace esto muy simple, implementándose de igual forma no importa de que lista se trate.

En los ejemplos 5 y 6, se puede apreciar la implementación:

function btnEj5SeleccionarPorValor_OnClick() {

    var valor = $('#txtEj5').val();
    
    $('#Ej5Select').val(valor);

}

function btnEj6SeleccionarPorValor_OnClick() {

    var valor = $('#txtEj6').val();

    $('#Ej6Select').val(valor);

}

Si se escribe un valor correcto en el TextBox, solo hará falta asignar el val() al selector del control y eso es todo.

Listas ASP.NET

Hasta ahora hemos estado trabajando en los ejemplos con controles html, pero se debió a que operar con estos o con el control de lista o combo del asp.net es idéntico.

En el ejemplo 7 se podrá apreciar justamente este punto:

 

        function btnEj7Agregar_OnClick() {

            var ej7Texto = $('#txtEj7Texto');
            var ej7Valor = $('#txtEj7Valor');

            var newItem = $('<option/>').text(ej7Texto.val()).val(ej7Valor.val());
            $('#<%=Ej7Select.ClientID%>').append(newItem);

        }

        function btnEj7Seleccion_OnClick() {

            var list = new Array();

            $.each($('#<%=Ej7Select.ClientID%> :selected'), function() {

                var msg = 'texto: {0}, valor: {1} 
'.format($(this).text(), $(this).val());
                list.push(msg);

            });

            $('#Ej7Resultado').html(list.join(''));

        }
        
        function btnEj7RemoverSeleccion_OnClick() {

            $.each($('#<%=Ej7Select.ClientID%> :selected'), function() {

                $(this).remove();

            });
        }

Aplicar selectores a un control de asp.net solo requiere el uso de la propiedad ClientID, si es que se usa el id del control para acceder al mismo, esto se aplica por si asp.net renombra esta propiedad al realizar el render del html que envía al cliente.

 

Código de Ejemplo

 

domingo, 17 de abril de 2011

[jQuery] Por donde comenzar

 

Introducción

jQuery es una de las librerías muy mencionada en los ultimo tiempo para el desarrollo de aplicaciones web.

Usar javascript de forma estándar puede ser algo bastante tedioso ya que no es una sintaxis del todo amigable para el trabajo diario, o al menos para quien esta acostumbrado a programa en un lenguaje amenos como ser C# o VB.NET.

Es por eso que surge jQuery, para solventar este problema, siendo el mas conocido entre los frameworks de javascript, (esta se gano su lugar en los témplate para la creación de proyectos como son los utilizados en aplicaciones con ASP.NET MVC), y el que dio impulso a la utilización de este tipo de frameworks,  vale aclarar además que también existen otro como ser: Prototype, MooTools, etc

Este articulo en particular se sumara a los miles que existen publicados para aportar un punto de inicio para quienes aun no conocen la magia de esta librería.

Aquí no se pretende explicar cada unos de los aspectos de jQuery, porque solo el tema se selectores es enorme y muy variado, sino que iremos a casos concretos, y analizaremos particularidades en el uso de la librería.

jQuery es muy amplio, con mucha flexibilidad, cuando la usen verán que no hay una sola forma de hacer las cosas, a veces se pueden aplicar un selector con distintas combinaciones y todas estarán correctas.

Es por eso que es necesario recurrir a la fuente y consultar la documentación provista por la propia librería en su sitio web: jQuery

Para empezar veremos dos puntos básicos que afectan a la interacciones de asp.net y javascript, luego continuaremos con el análisis de dos controles simples para entrar en tema.

 

1 – Acceder a los controles de asp.net

Algo que debe conocerse cuando se trabaja con controles desde javascript es como hacer referencia a estos.

Por ejemplo, si en el html de una pagina se define:

<input id="Text1" type="text" />

desde javascript podría seleccionar el control usando:

var text1 = document.getElementById('Text1');

de esta forma se seleccionado el control cuando se trata de uno del tipo html, pero que sucede si ahora se tiene un control de asp.net, aquí ya no somos quienes controlamos el render del control, por lo tanto el ID asignado al mismo puede variar.

Muy bien, ahora si realizamos unas pruebas y ponemos un asp:TextBox en una página

<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>

al acceder desde el browser se vera como

<input name="TextBox1" type="text" id="TextBox1" />

ups, pero que sucedió aquí el id no se modifico, seguro pensaran que estoy mintiendo, pues bien, lo que sucede es que en algunas situaciones asp.net no cambie el id del control, porque en este caso no lo requiere, el verdadero problema se presente cuando este control esta contenido dentro de ciertos contenedores, como ser: un User Control, la Master Page, o controles que repiten un témplate, como ser el ListView, GridView, Repeater, etc

Entonces que sucede ahora si se crear un User Control (WebUserControl1.ascx) con el textbox dentro del mismo y se lo ubica en una pagina, al acceder al código del browser se obtendrá

<input name="WebUserControl11$TextBox1" type="text" id="WebUserControl11_TextBox1" />

Ahora si se comprueba como asp.net modifica el id asignado al control en tiempo de diseño, asp.net necesito ponerle un prefijo con el nombre del User Control para que este sea único, ya que en la pagina puede usarse mas de un mismo user control, sino redefine el id puede haber colisiones en los nombres.

Como se haría para seleccionar este control sino se conoce previamente el id que será generado, pues bien, se dispone en asp.net de la propiedad ClientID, siendo usada de la siguiente forma:

var userControlText1 = document.getElementById('<%=TextBox1.ClientID%>');

al inspeccionar el código resultante en el browser se obtendrá

var userControlText1 = document.getElementById('WebUserControl11_TextBox1');

el tag <%=  %> permite ubicar allí el valor de la propiedad ClientID.

Si bien esto que comento parece un dato menos, es bastante importante cuando se comienzan a dar los primeros paso en javascript mezclado con controles del asp.net

 

2 – Acceder a controles asp.net desde un archivo .js

Continuando con el tip del punto anterior, avanzaremos en un tema que por ahí pueda generar dificultades a la hora de ordenar el código.

En algunas oportunidades uno requiera hacer uso de archivos .js para llevar allí el código javascript y trabajarlo de forma separada al html que esta en el aspx, pero es aquí donde empiezan los problemas.

Resulta que si se hace uso del tag <% %>, este solo puede ser aplicado dentro de la página donde se hace el render por parte de asp.net, o sea solo funciona dentro del aspx

El archivo .js es referenciado por el aspx, pero este no se incluye en el proceso de render, por lo tanto el ClientID nunca será reemplazado.

Pero hay una solución a este punto, la cual consiste en dejar la definición del tag <% %> dentro del aspx, pero que la misma solo asigne a una variable javascript el nombre del control, luego sera usada en el .js para así poder tomar el control y trabajarlo.

En la carpeta “Ejemplo2” esta la implementación del código de ejemplo, se observara la declaración de las líneas

<script type="text/javascript">

    var TextBox1 = '<%=TextBox1.ClientID%>';

</script>

en donde se asigna en la pagina aspx el nombre como string, para luego dentro del .js usar

function ObtenerValor() {

    var text1 = document.getElementById(TextBox1);
    alert(text1.value);

}

Es necesario apreciar como cambio la selección al usar el getElementById(), usando ahora el nombre de la variable.

El único problema que se presenta es que por cada control que se quiera usar dentro de .js será necesario crear una variable en la pagina que incluya el ID que asp.net asigna.

 

3 – Obtener y asignar el valor de un Texbox

Seguramente se preguntaran “cuando comenzamos”, es cierto hasta aquí se presentaron temas mas relacionados con javascript, que al propio jquery, pero eran necesario tenerlos presente ya que estos también afectan al desarrollo.

Bien, comencemos con algo simple.

Seleccionemos el valor de un TextBox, copiando el contenido a otro:

[HTML]

<form id="form1" runat="server">
    <table>
        <tr>
            <td>
                <input id="txtInfo" type="text" />
            </td>
            <td> 
                <input id="btnMostrar" type="button" value="button" onclick="Mostrar_OnClick();"/>
            </td>
            
        </tr>
        <tr>
            <td colspan="2"> 
                <input id="txtInfoCopia" type="text" />
            </td>
        </tr>
    </table>
</form>

[JavaScript]

function Mostrar_OnClick() {

    var info = $('#txtInfo').val();

    $('#txtInfoCopia').val(info);
    
}
 

como se observa jquery lo hizo bien simple.

Es preciso conocer que cuando uno selecciona un control y lo hace por el atributo “id” debe anteponer el “#”, este es uno de los tanto selectores tiene jquery que iremos viendo.

Para que esto funcione es necesario contar con la librería, en este caso se encuentra en la línea

<script src="../script/jquery-1.5.2.min.js" type="text/javascript"></script>

por lo general se sitúa en la propia pagina, pero también es común verlo en la Master Page para que todas incluyan la librería, y no se tenga que declarar en cada una particularmente.

Y que sucede si se tratan de controles de asp.net, bien es igual de simple, pero conociendo lo que vimos en el punto: “1 – Acceder a los controles de asp.net”, se obtendría la misma funcionalidad usando:

[JavaScript]

function MostrarASPNET_OnClick() {

    var info = $('#<%=txtInfoASPNET.ClientID%>').val();

    $('#<%=txtInfoCopiaASPNET.ClientID%>').val(info);

}

Avancemos un poco inicializando los textbox, para hacerlo individualmente se podría aplicar algo como esto:

[JavaScript]

function LimpiarASPNET_OnClick() {

    $('#<%=txtInfoASPNET.ClientID%>').val('');

    $('#<%=txtInfoCopiaASPNET.ClientID%>').val('');

}

es idéntico a lo que ya se viene viendo solo que no se le pasa valor

Y si se quiere limpiar el contenido de todos los textbox, se deberá asignar uno a uno?, no es necesario, hay técnicas mucho mas simples:

[JavaScript]

function LimpiarTodos_OnClick() {

    $(':text').val('');

}

aquí se puede ver otro selector distinto proporcionado por jQuery, en este caso se trata de un selector por tipo text el cual aplicara el valor a todos los controles que encuentre del tipo textbox.

Ahora bien, lo lindo que tiene esta librería es que no hay una sola forma de hacer esto, si se revisa la documentación: :text Selector, menciona que usar $('[type=text]') o $('*:text') y también $('input:text') son equivalentes, pero por simplicidad en la escritura se aplica :text

Nota: los ejemplos de esta sección se encuentra en el “Ejemplo 3” del código publicado.

4 – Trabajar con controles Label

Asignar un valor a un label difiere un poco de como se haría a un TextBox.

En el ejemplo de la carpeta “Ejemplo 4” se encontrara una muestra de como trabajar con este otro control.

en la pagina se agrego un label html

<label id="lblInfoCopia" />

y uno de asp.net

<asp:Label ID="lblInfoCopiaASPNET" runat="server"></asp:Label>

accederlo de forma individual no representa mayor problema, salvo por el hecho de cambiar el val() por el html() para tomar o asignar un valor.

Pero el seleccionar todos los labels de la pagina no es tan directo, ya que se renderiza diferentes en html estos controles, si se analiza el código generado en el browser se notara que el label de html sigue siendo un label, pero el de asp.net no lo es, ya que es transformado a un tag <span> cuando se convierte

Es por esto que debe seleccionarse distinto cada control.

[JavaScript]

function Mostrar_OnClick() {

    var info = $('#txtInfo').val();

    $('#lblInfoCopia').html(info);

}

function MostrarASPNET_OnClick() {

    var info = $('#<%=txtInfoASPNET.ClientID%>').val();

    $('#<%=lblInfoCopiaASPNET.ClientID%>').html(info);

}

function LimpiarASPNET_OnClick() {

    $('#<%=txtInfoASPNET.ClientID%>').val('');

    $('#<%=lblInfoCopiaASPNET.ClientID%>').html('');

}

function LimpiarTodos_OnClick() {

    $(':text').val('');
    $('label').html('');
    $('span').html('');
}

 

 

Conclusión

Hasta aquí hemos tenido una introducción general a las particularidades del uso de javascript cuando se tratan controles asp.net.

También hemos visto como tratar dos controles muy usados en las paginas como son los textbox y labels.

En próximos artículos veremos mas controles ya sean html o asp.net, como adjuntar evento y recorrer el resultado de una selección para trabajar con cada uno de sus ítems

 

Código Ejemplo


 

miércoles, 3 de noviembre de 2010

[ASP.NET][jQuery] Validación sin Postback

 

Introducción


Uno de los principales problemas en un desarrollo web es implementar una confirmación del usuario, especialmente cuando estas necesitas ser realizadas en el servidor.

Acciones implementadas en botones que requieren de una conformación del usuario puede ser un problema, ya que estas necesitan ir al servidor, aplicar la validación, retornar o registrar el script que mostraría al usuario el mensaje javascript de confirmación y ante la aceptación, realizar nuevamente el postback al servidor

 

Solución


El uso de jquery puede aportarnos un alivio a esta problemática, concretamente con el uso de la funcionalidad de $.ajax, el cual no permitirá invocar funcionalidad del servidor para realizar validaciones sin postback de la pagina

El resultado de la validación podrá ser validado y allí mismo mostrar el mensaje de confirmación, si este es aceptado se continua con la operación normalmente.

 

Ejemplo de código


[C#] 
 

viernes, 16 de julio de 2010

[ASP.NET] Mantener la Session Activa Indefinidamente

 

Introducción


El objetivo que persigue el articulo es demostrar como mediante llamadas asíncronas realizadas por medio de la librería de jquery se puede mantener la Session activa en el servidor de forma indefinida sin que este expire en un tiempo determinado.

 

Mantener la Session Activa


Asp.net expira la Session de un usuario cuando un tiempo prolongado de inactividad indicaría que ya no se esta usando la pagina, pero a veces es necesario permitir que el usuario tome varias horas sin actividad, aunque en la configuración del servidor el timeout este definido en un tiempo reducido.

La idea del ejemplo es realizar de forma transparente para el usuario, y sin que se refresque la pagina, una invocación al servidor, para que este registre dicha actividad.

Para lograr el objetivo se hará uso de dos librerías de jquery:

- la principal realizará las invocaciones a los WebMethod definidos en la pagina, usando la funcionalidad de $.ajax

- la otra librería permitirá especificar desde javascript el intervalo de tiempo en que debe invocarse al método expuesto en el servidor web, jQuery Timers 

[javascript]

<script language="javascript" type="text/javascript">

        $().ready(function() {

        $(document).everyTime(3000, function() {
        
                $.ajax({
                    type: "POST",
                    url: "ValidarSession1.aspx/KeepActiveSession",
                    data: {},
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    async: true,
                    success: VerifySessionState,
                    error: function(XMLHttpRequest, textStatus, errorThrown) {
                        alert(textStatus + ": " + XMLHttpRequest.responseText);
                    }
                });
                
            });

     
        });

        var cantValidaciones = 0;

        function VerifySessionState(result) {

            if (result.d) {
                $("#EstadoSession").text("activo");
            }
            else
                $("#EstadoSession").text("expiro");

            $("#cantValidaciones").text(cantValidaciones);
            cantValidaciones++;

        }

        function SessionAbandon() {

            $.ajax({
                type: "POST",
                url: "ValidarSession1.aspx/SessionAbandon",
                data: {},
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                async: true,
                error: function(XMLHttpRequest, textStatus, errorThrown) {
                    alert(textStatus + ": " + XMLHttpRequest.responseText);
                }
            });
            
        }
    </script>

 

[C#]

public partial class ValidarSession1 : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Session["datos"] = true;
    }


    [WebMethod()]
    public static bool KeepActiveSession()
    {
        if (HttpContext.Current.Session["datos"] != null)
            return true;
        else
            return false;
    }

    [WebMethod()]
    public static void SessionAbandon()
    {
        HttpContext.Current.Session.Remove("datos");
    }

}

En el código puede observarse los WebMethod expuestos en la página, y como son invocados desde javascript de forma asíncrona, usando una llamada ajax, mediante el uso de $.ajax

 

Consideraciones de los Ejemplos


Dentro de ejemplo de código se encontraran dos páginas aspx, ambas realizan la misma operación, solo que aplican distintas técnicas.

En la pagina ValidarSession1.aspx se verifica explícitamente que determinada key de la session esta disponible. La idea de este ejemplo es demostrar que tanto la pagina como los servicios web que se están usando comparten la misma Session y se puede acceder a los datos allí guardados

La pagina ValidarSession2.aspx, si bien la forma de comunicarse es la misma, la validaciones de la session ha cambiado, aquí no se usa una key determinada, sino que se valida el objeto de forma general.

En el ejemplo para que sea practico se estableció un tiempo de 3000 ms (3 seg), para que valide la Session, pero si la idea es mantener la session activa con especificar un tiempo cercano al definido en el expiración de la sesión alcanzaría.

Por ejemplo si se determino en el IIS que el sitio tiene un timeout de session en 20min, especificando un tiempo de 15000 ms (15 min) seria suficiente para evitar que la session expire.

La solución fue desarrollada con Visual Studio 2008.

 

[C#] 
[VB.NET]