lunes, 30 de abril de 2012

[ASP.NET] PopUp Filtro – usando window.open()

 

Introducción

El objetivo del artículo apunta a demostrar como implementar la búsqueda de un determinado ítem haciendo uso de ventanas que se abran en popup.

Para la implementación se utilizara la funcionalidad de window.open() provista por javascript.

El ejemplo consiste en un listado de producto, pudiendo ser filtrados mediante una ventana popup que lista los proveedores.

El código fue implementado de dos formas distintas, si bien son muy parecidas tienen sutiles cambios, estas dos formas las denomine:

  • Selección con evento
  • Selección sin evento

Imagino se preguntaran del porque de esta diferencia del uso de un evento o no, básicamente difieren en el uso de controles asp.net (con evento) o tag de html (sin evento), cada alternativa cambia la forma en que se implementa la solución, en concreto la forma en que se toma el ítem elegido.

Empezaremos analizando la parte de la implementación que es común en ambos casos para luego ir a los detalles que afectan el usar un control de asp.net o uno de html

Abrir ventana de búsqueda

La definición del botón de búsqueda se logra adjuntando el evento click de jquery al tag <input>, como se refleja en la imagen

Esta acción lanzara la ventana de búsqueda que se ha implementado mediante el uso de window.open()

 

Filtro de productos

Una vez seleccionado el proveedor en la ventana de búsqueda esta acciona, o ejecuta, el botón de filtro, el cual se ha implementado, en en la pagina original, es decir la ventana hija invoca un boton en la ventana padre.

 

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

    //
    // muestro la descripcion del proveedor
    //
    Suppliers supplier = NorthwindData.GetSupplierById(txtId.Text);

    string CompanyName = "";
    if (supplier != null)
    {
        CompanyName = supplier.CompanyName.Encode();
    }

    //
    // asigna el nombre al label que esta fuera del updatepanel
    //
    string script = @"$('#{0}').text('{1}');";
    script = string.Format(script, lblSupplierName.ClientID, CompanyName);

    ScriptManager.RegisterStartupScript(this, typeof(Page), "filterinfo", script, true);

}
private void LoadGridProducts()
{
    int? SupplierId = null;

    int id = 0;
    if (Int32.TryParse(txtId.Text, out id))
    {
        SupplierId = id;
    }
    

    gvProducts.DataSource = NorthwindData.GetProductsBySupplier(SupplierId);
    gvProducts.DataBind();
}

Algo que quizás no parezca tener sentido al principio es porque el nombre del proveedor seleccionado es asignado mediante código javascript (o mejor dicho jquery), en lugar de hacerlo directamente, bueno esto se deba al uso del control UpdatePanel, el label donde se asigna el nombre del proveedor seleccionado esta por fuera del panel lo cual requiere que al asignar un valor sea realice de forma indirecta.

 

Selección sin evento (usando html <img>)

Empezaremos analizando como realizar la selección usando un control simple de html, en este caso en el grid de proveedores se usa el tag <img> dentro del item template

Pro medio de la ayuda de jquery se asocia el evento click, usando el atributo class del <img> como selector

<script type="text/javascript">

    $(function() {

        $('#<%=gvSuppliers.ClientID %> .imgSelection').click(function() {

            var supplierID = $(this).attr('SupplierID');
            
            var tr = $(this).parent().parent();
            var companyName = $('td:eq(2)', tr).text();

            window.opener.$("[id*='txtId']").val(supplierID);
            window.opener.$("[id*='lblSupplierName']").text(companyName);

            window.opener.$("[id*='btnFiltrar']").click();

            window.close();
        })

    });

</script>

Como el evento lo lanza el propio tag <img> se puede acceder a este mediante $(this) tomando el atributo, pero para recuperar información adicional debe subirse hasta el tag <tr> de la tabla que genera el gridview para así poder acceder a los datos de las celdas, el td:eq(2), hace referencia a la segunda columna del grid

La integración de jquery con javascript nos permite realizar una búsqueda en la página padre usando window.opener, y mediante el *= sobre el id, una búsqueda aproximada, similar a usar el like.

en las ultimas dos líneas se lanza el evento click del boton de filtro y se cierra la ventana.

 

Selección con evento (uso control asp.net ImageButton)

A diferencia del caso sin evento, en este se hace uso de un control de asp.net para seleccionar el proveedor del grid, como se puede observar en la imagen

Este simple cambio impacta en la forma en que se implementa el resto

<script type="text/javascript">

    function SupplierSelected(supplierID, companyName) {

        window.opener.$("[id*='txtId']").val(supplierID);
        window.opener.$("[id*='lblSupplierName']").text(companyName);

        window.opener.$("[id*='btnFiltrar']").click();

        window.close();
    }

</script>

El javascript usado se reduce, ya no se implementa la búsqueda en al tabla del html que genera el gridview, pues se dispone acceso directo al control desde código .net

protected void gvSuppliers_SelectedIndexChanging(object sender, GridViewSelectEventArgs e)
{
    
    int supplierId = Convert.ToInt32(gvSuppliers.DataKeys[e.NewSelectedIndex].Value);

    string companyName = gvSuppliers.Rows[e.NewSelectedIndex].Cells[2].Text;


    string script = @"$(function(){{
                        SupplierSelected('{0}','{1}');
                    }});"; //se define {{ para poder usar el string.Format()

    script = string.Format(script, supplierId, companyName.Encode());

    ScriptManager.RegisterStartupScript(Page, typeof(Page), "popupclose", script, true);

}

La asignación del valor de retorno no es tan directa, sino que debe ser escrita en el retorno del postback del evento, esto es necesario ya que el window.opener solo puede usarse desde código cliente.

 

Código
[C#]
 

15 comentarios:

  1. Buscando cómo solucionar el problema de la paginación de un GridView he dado con tu blog que me parece una pasada.

    Muchas gracias y lo anoto al reader ;-)

    ResponderEliminar
  2. Muy bueno, pero tendras el codigo para vb.net?

    Muchas gracias

    ResponderEliminar
  3. muy bueno ya me las arregle para vb.net que no era nada de cambios, ahora como puedo pasar parametros desde esa llamada a mi otra ventana qu se abre?

    ResponderEliminar
  4. hola David

    no entendi, que otra ventana se abre ?
    o sea tienes la ventana padre, que es la principal y la ventana hija, no hay otra

    simpre suas el window.opner para comunicar o sino defines datos en que querystring en la url de la pagina hija

    saludos

    ResponderEliminar
  5. Que tal Leandro, Tu Blog esta muy interesante, gracias por todo lo q aportas.

    Una consulta cuando se abre la pagina con window.oper no se puede obtener acceso a los controles de la pagina previa con Page.PreviousPage?

    ResponderEliminar
  6. hola OscMop

    es que al usar el window.open lo haces desde javascript por lo que no hay un postback

    para acceder a los controles de la ventana padre lo haces desde codigo cliente usando el

    window.opener

    desde el servidor deberias enviar los datos en la url como parte del querystring, no viajan por post

    saludos

    ResponderEliminar
  7. Hola Leandro, ahora que el chrome ha quitado el showModalDialog esta solucion me parece buena opcion a menos que tengas otra... por otro lado como haria si la ventana hija lanza otra ventana como devolver datos de la segunda hija referenciando a la primera hija...
    gracias por tu respuesta y haber si tienes otra opcion por lo del showmodal dialog

    ResponderEliminar
  8. hola Leandro,
    ya di con la solucion solo hay q referenciar el form de esta manera
    window.opener.$("[id*='wfCuadroNecesidadBnd']");

    sobre lo del retiro del chrome ojala haya otra opcion aparte de esta haber sorprendenos

    saludos

    ResponderEliminar
  9. buen día disculpa Leandro, están utilizando la Db de Northwindb

    ResponderEliminar
    Respuestas
    1. hola
      Si asi es, es mas la db la tienes dentro de la carpeta App_Data
      Es uan db de Sql Compact
      saludos

      Eliminar
    2. buenas leandro tu depronto me podrias ayudar con una sesoria es que no pude desarrollar el ejemplo y lo necesito para un proyecto quedo atento a tu comentarios gracias

      Eliminar
  10. buen dia Leandro estoy tratando de hacer lo mismo pero no con windows forms habra alguna forma de hacer eso pero en web aplication, tendras un ejemplo de ello

    ResponderEliminar
    Respuestas
    1. hola
      Podrias hacerlo si comunicas los forms como comento en el articulo
      Comunicar Formularios
      saludos

      Eliminar
  11. Leandro, buenas noches, estoy intentando aplicar este ejemplo, veo que en la página de los productos, al lado del botón buscar, tienes un txt, bien, no se si estoy leyendo mal el código, pero no veo que ese txt haga nada al momento de llamar el popup, entonces, mi idea es aplicar un doble filtro, es decir: Si escribe un texto en el campo y presiona buscar, pasar de alguna manera ese valor al aspx popup y que este valor filtre los registros mostrados en el grid, para que luego, al seleccionar un registro en el grid, aplique el filtro en el aspx padre, entonces, desconozco cómo pasar el valor del aspx padre al aspx popup por medio de Js, sí me puedes echar una mano... Agradecido...

    ResponderEliminar
  12. Hola Leandro, es un gusto saludarte, oye tengo una duda sobre tu ejemplo, ¿solo se puede realizar estas acciones desde la master page?

    ResponderEliminar