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

 

20 comentarios:

  1. Leandro,

    Es mi primer comentario en tu blog después de leer muchos de tus artículos , muchas gracias de verdad has sido el apoyo en pequeños y grandes problemas,me apoyo mucho de tu blog y de los foros de desarrollo de MSDN y siempre estas ahí para dar tu aporte y en la gran mayoría de veces la solución al inconveniente,

    Hoy quería comenzar a aprender el mundo de JQuery, leí varios artículos, pero humildemente me quedo con el tuyo !!

    Lo que quiero decir, es gracias por todo, es mas que merecido que seas un MVP y animo para que sigas publicando artículos,

    ResponderEliminar
  2. hola Cristian Perez

    me alegro que sea util el articulo, estoy viendo de plantear algunos temas mas que me quedaron, quizas mas centrado sobre json, y la interaccion de javascript con .net para trabajar datos

    saludos

    ResponderEliminar
  3. Muchisimas gracias Leandro por tu infromación, no sabes cuanto me ayudo.
    Queria preguntarte como puedo enviar lo que selecciono en una lista seleccion Multiple a otra lista de seleccion multiple. En tu ejemplo los imprimes
    var msg = 'texto: {0}, valor: {1}
    '.format($(this).text(), $(this).val());
    list.push(msg);

    ResponderEliminar
  4. Leandro ya solucione mi duda solo modifique donde imprimes los datos y los mande a una lista.

    ResponderEliminar
  5. Hola Leandro, encontre muy interesante tus ejemplos ya q yo estoy haciendo algo similar pero con json, lo q necesito es traer desde la BD las opciones seleccionadas por el usuario anteriormente para que estas puedan ser modificadas en el formulario de actualizacion de datos, logro traer estos datos por json, pero no se como mostrarlos (para mostrar seleccionados en el multiselect solo lo q el usuarioha seleccionado y q los q no se muestren no seleccionados, es decir solo mostraer los q trae desde la BD por ejemplo si venen 3 opciones mostrar esas 3 como seleccionadas en el multiselect y los demas de la lista dejarlos sin seleccionar) como puedo lograr esto?? agradeceria mucho tu ayuda/guia de antemano gracias.

    ResponderEliminar
  6. seme olvidaba todo lo anterior es con un multiselect html

    ResponderEliminar
  7. hola Rodrigo

    podrias aplicar un

    $.each(list, function(){

    //aqui asignas la seleccion al control

    });

    de esta forma lo que viene por json lo seleccionarias en el multiselect

    Nota: quizas podrias hacer un clear de la seleccion antes de volver a seleccionar ante algun refresh

    saludos

    ResponderEliminar
  8. gracias leandro soy nuevo con json y justamente es ese mi problema como le asigno los valores q vienen desde la base de datos para q estos aparescan seleccionados eso es lo q no puedo lograr hacer asignarle la seleccion al control, con esta funcion traigo los select de la bd, pero no se como asignar los seleccionados si no fuera mucho pedir me podrias graficar como asignar los seleccionados dentro del .each?? la funcion con la q traigo los valores de la bd es esta:


    $(document).ready(function(){
    $("#selectNombreCurso").change(function(){
    var textIdPrograma = $("#textIdPrograma").val();

    valores= 'textIdPrograma='+textIdPrograma;
    $.ajax({
    type: "POST",
    url: "../auxiliar/updtSubcompetenciaProg.php",
    data: valores,
    dataType: "json",
    success: function(aResponseData, aStatus, aJqX){

    if (aResponseData!='')
    {
    $("#textCompetenciaAsoc").val( aResponseData[0].textCompetenciaAsoc );
    }
    else
    {
    $("#textCompetenciaAsoc").val( '' );
    }
    }
    })
    })


    de antemano gracias

    ResponderEliminar
  9. hola Rodrigo

    cuando invocas el php que es lo que retorna como json, es un array ?

    podrias dentro de la function del success, la linea

    debugger;

    con esto se detendra el codigo y podrias inspeccionar que devuelve como respuesta para asignarlo a los contorles

    Nota: usa el IE para que esto suceda

    usar el $("selector").val(valor)
    esta correcto, pero deberias conocer como llega el json

    saludos

    ResponderEliminar
  10. hola leandro, los valores me llegan como array en el array aResponseData me llegan los tres valores correspondientes con jason, esto lo comprobe con el firebug de firefox, me llegan los tres valores y estos tre valores q estan dentro del arreglo aResponseData y estos 3 valores quiero mostrarlos dentro de mi control multiselect: $("#textCompetenciaAsoc")

    pero lo q no se es como debe ser la sintaxis dentro del .each para q estos valores se me muestren como seleccionados en mi multiselect $("#textCompetenciaAsoc") , esa es mi duda porfavor si me pudieras ayudar ya q traigo los datos ahora solo necesito mostrarlos como seleccionados dentro del multiselect, de antemano muchas gracias y quedo atento a tu respuesta, gracias.

    ResponderEliminar
  11. hola Rodrigo

    podrias usar

    $.each(aResponseData, function(){

    //aqui asignas el this al control

    });

    pero alli veo que al definir
    $("#textCompetenciaAsoc")
    porque le pones "text" como prefijo? o sea que clase de multiselect lleva el nombre de text

    saludos

    ResponderEliminar
  12. hola leandro, intente hacerlo de la manera q tu me indicas:

    $.each(aResponseData, function(){
    $("#textCompetenciaAsoc").val( aResponseData[0].textCompetenciaAsoc );
    });

    pero no me marca como seleccionados los tres valores q traigo con json(q si vienen) pero no me los muestra seleccionados en mi multiselect textCompetenciaAsoc, como entonces debo asignarle los valores?? de bantemano gracias y quedo atento a tu respuesta saludos,

    ResponderEliminar
  13. Leandro tambien lo he intentado asi:

    $.each(aResponseData, function(){

    var selectMultiple = (aResponseData[0].textCompetenciaAsoc);

    $("#textCompetenciaAsoc option").removeAttr("selected");
    $("#textCompetenciaAsoc option[value="+selectMultiple+"]").attr("selected","selected");
    $("#textCompetenciaAsoc option").removeAttr("selected");
    $("#textCompetenciaAsoc option[value="+selectMultiple+"]").attr("selected","selected");
    });

    pero tampoco me muestra seleccionados los valores en mi multiselect pero el array de json viene con los datos, pero estos no se me muestran seleccionados en mi multiselect, de q manera tendria q pasarle los valores entonces?? agradeceria mucho tu ayuda, ya q estoy entrampado con esto, quedo atento a tu respuesta de antemano gracias

    ResponderEliminar
  14. hola Rodrigo

    $.each(aResponseData, function(){
    $("#textCompetenciaAsoc").val( this.textCompetenciaAsoc );
    });

    que control es el textCompetenciaAsoc? es un <select multiple /> o es algun otro tipo

    saludos

    ResponderEliminar
  15. hola leandro si el textCompetenciaAsoc es un select multiple, lo hice como me indicaste y me resulto, pero solo me muestra seleccionado el ultimo de los 3 valores q me trae desde json pq sera?? te adjunto mi code para ver si me puedes ayudar porfavor:

    http://jsfiddle.net/3Rsrd/

    esa es mi funcion completa y llene el multiselect como me indicaste pero como te digo solo me deja seleccionado el ultimo valor de los 3 q vienen desde la funcion json, q estoy haciendo mal?? porfavor quedo atento a tu respuesta de antemano gracias, saludos

    ResponderEliminar
  16. Hola Leandro, disculpa q te vuelva a escribir nuevamente, pero como lo hago para q me mantenga seleccionados los 3 valores del multiselect q traigo desde la bd con json??? ya q solo me deja seleccionado el ultimo valor q traigo pero al hacerle alert a la variable del multiselect me selecciona las tres opciones q vienen, es decir en el primer alert me muestra marcada la opcion 1 en el segundo alert me selecciona la opcion 2 y en el tercer alert me selecciona la opcion 3 y esta ultima es la q queda seleccionada definitivamente, pero como lo hago para q me muestre las tres opciones seleccionadas de una vez?? en esta url esta el codigo completo de la funcion (ya q por aca no me deja pegar el codigo completo):

    http://jsfiddle.net/3Rsrd/

    de antemano gracias Leandro y quedo atento a tu respuesta, saludos

    ResponderEliminar
  17. hola Rodrigo

    podrias poner en jsfiddle como es el html de la pagina

    porque es raro que vaya seleccionado de a uno pero luego desmarque cuando se seelcciona otro, si es un control que permite multi seleccion deberia dejar todos marcados

    saludos

    ResponderEliminar
  18. Hola leandro,es super raro, ya q lo tengo definido como multiselect, aca te adjunto el control html y la funcion json:

    http://jsfiddle.net/3Rsrd/1/
    porfavor a ver si me ayudas a pillar la solucion ya q estoy entrampado con este lio, de antemano gracias y quedo atento a tu respuesta, saludos

    ResponderEliminar
  19. Gracias Amigo por la explicación!!

    ResponderEliminar
  20. Lo que me fascina de tu código es lo encapsulado que está en funciones... genial!

    ResponderEliminar