27.8.08

Objeto Javascript para manipular ComboBox

Hoy les acerco un objeto Javascript que permite manipular ComboBox de manera un tanto más sencilla y práctica

Entre sus propiedades, éste permite:

  • Crear el combo a través de un par de métodos y con algunas propiedades, de manera dinámica.
  • Obtener el valor de la opción seleccionada, sus atributos y/o el texto de la opción.
  • Eliminar todas o algunas de las opciones.
  • Ordenar las opcines por su valor o por su texto identificatorio.
  • Seleccionar la opción del combo, basándose en el valor o el texto de la misma.

El código:


/** Documento Javascript
Funciones para tratar objetos SELECT

Autor: Julio Gonzalez
Fecha: 22/08/2008
*/

$CB = {
/* metodo interno */
__ctrlOBJ:function(ob) {
 if( typeof ob != 'object' ) { return false; }
 if( ! ob ) { return false; }
 return true;
},

/* metodo interno */
__isArray:function(ob) {
 return (ob != null && typeof ob == "object" && 'splice' in ob && 'join' in ob);
},

/* metodo interno */
__isObject:function(ob) {
return (ob != null && typeof ob == "object");
},

/* metodo interno */
__getIndexByValue:function(ob, val, sensitive) {
 if(!this.__ctrlOBJ(ob)) { return null; }
 if(arguments.length < 3) { sensitive = false; }
 var ve;
 val = (sensitive)?val:val.toLowerCase();
 for(var i=0, len=ob.length; i < len; i++)
 {
     ve = (sensitive)?ob.options[i].value:ob.options[i].value.toLowerCase();
     if( ve == val ) {    return i; }
 }
 return null;
},

/* metodo interno */
/* seleccionar una opcion por el texto de la opcion */
__getIndexByText:function(ob, txt, sensitive) {
 if(!this.__ctrlOBJ(ob)) { return null; }
 if(arguments.length < 3) { sensitive = false; }
 var ve;
 txt = (sensitive)?txt:txt.toLowerCase();
 for(var i=0, len=ob.length; i < len; i++)
 {
     ve = (sensitive)?ob.options[i].text:ob.options[i].text.toLowerCase();
     if( ve == txt ) {    return i; }
 }
 return null;
},

/* elimina todos los elementos de un combo */
Clear:function(ob) {
 if(!this.__ctrlOBJ(ob))  { return false; }
 for(var i = ob.length - 1; i >= 0; i--)
 { ob.remove(i);  }
 return true;
},

/* borra una opcion buscandola por su value 
        sensitive (valor booleano) indica si la busqueda sera sensible a mayusculas/minusculas */
DeleteOptionByValue:function(ob, val, sensitive) {
 var i = this.__getIndexByValue(ob, val, sensitive);
 if(i==null) { return false; }
 ob.remove(i);
 return true;
},


/* borra una opcion buscandola por su value 
        sensitive (valor booleano) indica si la busqueda sera sensible a mayusculas/minusculas  */
 DeleteOptionByText:function(ob, txt, sensitive) {
 var i = this.__getIndexByText(ob, txt, sensitive);
 if(i==null) { return false; }
 ob.remove(i);
 return true;
},

/* retorna el texto de la opcion seleccionada */
TextSelectedOption:function(ob) {
 if(!this.__ctrlOBJ(ob) || !this.IsSelected(ob)) { return null; }
 return ob.options[ob.selectedIndex].text;
},

/* retorna el valor de la opcion seleccionada */
ValueSelectedOption:function(ob)   {
 if(!this.__ctrlOBJ(ob) || !this.IsSelected(ob)) { return null; }
 return ob.options[ob.selectedIndex].value;
},


/* retorna el objeto de la opcion seleccionada */
ObjectSelectedOption:function(ob) {
 if(!this.__ctrlOBJ(ob) || !this.IsSelected(ob)) { return null; }
 return ob.options[ob.selectedIndex];
},

/* retorna verdadero si el selectedIndex es > -1 */
IsSelected:function(ob)    {
 if(!this.__ctrlOBJ(ob)) { return false; }
 return (ob.selectedIndex > -1);
},


/* seleccionar una opcion por la propiedad value de la opcion 
        sensitive (valor booleano) indica si la busqueda sera sensible a mayusculas/minusculas  */
SelectByValue:function(ob, val, sensitive)
{
 var i = this.__getIndexByValue(ob, val, sensitive);
 if(i==null) { return false; }
 ob.selectedIndex = i;
 return true;
},


/* seleccionar una opcion por el texto de la opcion 
        sensitive (valor booleano) indica si la busqueda sera sensible a mayusculas/minusculas  */
SelectByText:function(ob, txt, sensitive)
{
 var i = this.__getIndexByText(ob, txt, sensitive);
 if(i==null) { return false; }
 ob.selectedIndex = i;
 return true;
},


/* objeto para crear el objeto necesario en CreateHTMLCombo */
ComboObject:{
 __cb:{id:'', name:'', attr:[], options:[]},
 setID:function(v) { this.__cb.id=v; },
 setName:function(v) { this.__cb.name=v; },
 addSelectAttribute:function(v) { this.__cb.attr.push(v); },
 addOption:function(txt, aAtt) {
     var ob={};
     ob.text=txt;
     ob.attr=aAtt;
     this.__cb.options.push(ob);
 },
 getComboObject:function() { return this.__cb; }
},


/* Crea el codigo html de un combo a partir de un obejto con la definicion de la etiqueta,
        y un array de objeto con el contenido de las etiquetas option.
        Datos del select
        - attr  array de pares (attr=value) con atributos del objeto (incluyendo los del usuario)
        - id        id del objeto select (obligatorio)
        - name  name dentro del <form>
   

        Datos de los options (Array)
        - text    texto de cada option
        - attr  array de pares (attr=value) con atributos del objeto (incluyendo los del usuario)
    */
CreateHTMLCombo:function(oSelDef) {
 if( !this.__isObject(oSelDef) ) { return null; }
 var aOp = oSelDef.options;
 if( !this.__isArray(aOp) ) {  return null; }
 /* define el select */
 if(typeof oSelDef.id != 'string') { return null; }
 var id = oSelDef.id.replace(/^\s+|\s+$/g,"");
 if(typeof oSelDef.name != 'string' || oSelDef.name.length==0) { oSelDef.name = id; }
 var htm = ['<select id="' + id + '" name="' + oSelDef.name + '"'];
 var aAttr = oSelDef.attr;
 if( this.__isArray(aAttr) ) {
     for(var i=0, len = aAttr.length; i < len; i++)
     {
         var tmp = aAttr[i].split('=');
         if(tmp.length > 1) {
             htm.push(' ' + tmp[0] + '="' + tmp[1] + '"');
         }
     }
 }
 htm.push('>');
     /* agrega los options */
 for(var i=0, len = aOp.length; i < len; i++)
 {
     var op = aOp[i];
     htm.push('<option');
     var aAttr = op.attr;
     if( this.__isArray(aAttr) ) {
         for(var e=0, len2 = aAttr.length; e < len2; e++)
         {
             var tmp = aAttr[e].split('=');
             if(tmp.length > 1) {
                 htm.push(' ' + tmp[0] + '="' + tmp[1] + '"');
             }
         }
         htm.push('>' + ((op.text)?op.text:'') + '</option>');
     }
 }
 htm.push('</select>');
 return htm.join('');
},

/* funcion interna */
/* acomoda un combo de acuerdo con el texto o el valor de sus options 
        sensitive (valor booleano) indica si la busqueda sera sensible a mayusculas/minusculas  */
__SortBy:function(ob, by, sensitive) {
 if(!this.__ctrlOBJ(ob) || !this.IsSelected(ob)) { return false; }
 if(!sensitive) { sensitive=false; }
 var b = new Array();
 var c = ob.getElementsByTagName('option');
 for ( var i in c )
 {
     try {
         b.push( { text:((by=='T')?c[i].text:c[i].value),
                      node:ob[i].cloneNode(true),
                      selected:ob[i].selected} );
     } catch(e) { continue; }
 }
 if(sensitive)
 {
     b.sort(function(opt1, opt2) {
         return opt1.text < opt2.text ? -1 : opt1.text > opt2.text ? 1 : 0;
     });
 }else{
     b.sort(function(opt1, opt2) {
         return opt1.text.toLowerCase() < opt2.text.toLowerCase() ? -1 :
                         opt1.text.toLowerCase() > opt2.text.toLowerCase() ? 1 : 0;
     });
 }
 this.Clear(ob);
 for ( var i in c )
 {
     try {
         var d = b.shift();
         ob.appendChild(d.node);
         if(d.selected) { ob.options[ob.options.length-1].selected=true;}
     } catch(e) { continue; }
 }
 return true;
},


/* acomoda un combo de acuerdo con el texto de sus options 
        sensitive (valor booleano) indica si la busqueda sera sensible a mayusculas/minusculas  */
SortByText:function(ob, sensitive) {
 return this.__SortBy(ob, 'T', sensitive);
},

/* acomoda un combo de acuerdo con el valor de sus options 
        sensitive (valor booleano) indica si la busqueda sera sensible a mayusculas/minusculas  */
SortByValue:function(ob, sensitive) {
 return this.__SortBy(ob, 'V', sensitive);
}
}

Su uso es bien sencillo:


<div id='j'></div>


<div><button type="button" onClick="GenCombo()">Generar Combo</button></div>
<div><button type="button" onClick="sortCB('T')">Sort por text</button></div>
<div><button type="button" onClick="sortCB('V')">Sort por value</button></div>

<script language="javascript">
/* creacion del combo mediante javascript */
cb = $CB.ComboObject;
//id del select
cb.setID('myCbo');
//atributos de la etiqueta <select>
cb.addSelectAttribute('class=prueba nodes')
cb.addSelectAttribute('size=5')
//definicion de los options
cb.addOption('W 1', ['value=33','selected=true', 'style=background-color:red;'])
cb.addOption('a 1', ['value=11'])
cb.addOption('e 2', ['value=123'])

//ejemplo de creacion del combo
function GenCombo() {
    var j = $CB.CreateHTMLCombo(cb.getComboObject())
    cbo = document.getElementById('j')
    cbo.innerHTML = j
    document.getElementById('myCbo').onchange=mostrar;
}

//ejemplo de ordenacion de combo
function sortCB(val) {
    alert(cbo.innerHTML)
    switch(val) {
        case 'T':
            $CB.SortByText(document.getElementById('myCbo'), true);
            break;
        case 'V':
            $CB.SortByValue(document.getElementById('myCbo'), true);
            break;
    }
    alert(cbo.innerHTML)
}

function mostrar()
{
    var ob = $CB.ObjectSelectedOption(this)
    alert(ob.innerHTML)
}

</script>

Pueden crear el combo mediante el uso de este objeto o pueden manipular uno existente en la página.

Personalmente, cuando se trata de combos dinámicos, cargo la página sin el combo y luego, mediante AJAX, busco el contenido del mismo y genero el combo dentro de un contenedor existente en la página, generalmente un SPAN.

3 Comentarios:

Anónimo dice...

me parece excelente tu aporte, solo tengo varias dudas, ya que apenas estoy iniciando en ajax.
1. Ya tengo la implementacion colocada en un archivo html, pero el codigo como se almacena?? como html, como js, como???
Puedo crear tantos combos requiera???

Julio González Seara dice...

Este objeto lo que hace es crear el codigo html de un combo mediante metodos y luego tu, al codigo resultante, lo pegas en el innerHTML de, por ejemplo, un span o un div o un td.

Pero esa no es su virtud principal. Su virtud es el manejo de la informacion escribiendo, por ejemplo, poco codigo para obtener el valor de la opcion elegida o su texto descriptivo u ordenar el combo por un criterio, o borrar uno o todos su elementos de forma menos tediosa que lo normal

Unknown dice...

Hola, me podrían ayudar por favor; tengo un combo con valores prestablecidos con sus correspondientes ID al momento de ordenarlos los texto se ordenan pero el ID que tienen ahora no es el mismo que tenían inicialmente y me interesa conservar los ID originales.
De ante mano gracias por su ayuda.