Comunidad de diseño web y desarrollo en internet online

Manejar combos multi-niveles con Javascript a partir de un objeto JSON

Buenas!, quería aportar hoy algo que hice hace algunos meses y que me ha sido a mí de mucha utilidad y es un método de cómo usar combos interactivos a partir de un árbol de JSON. Esto les podrá servir para crear combos interactivos más rápido con pocas opciones y pocos niveles.

Creo que los que ya han hecho combos interactivos con ajax saben que puede llegar a ser un dolor de cabeza, así que yo preferí hacerlo todo creando una clase para manejarlo en un sólo llamado.

En fin, aquí les mando el source del HTML y Javascript para crear uno de prueba
(en esta prueba uso 4 niveles: continente, país, cuidad, aldea) pero sólo 2 dos opciones tienen 4 niveles, las demás tienen 3, esto lo hago a propósito para que puedan ver cómo se comporta si los datos están incompletos.

Bueno aquí esta el código, abajo de todo explico las partes esenciales para generar la clase...
(index.html)

Código :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<title>Combos interactivos</title> 
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<style type="text/css">
body{ font-family: sans-serif }
span{ display: block; width: 100px; float: left; clear: left;}
select{ float: left;  }
</style>
</head>
<body>

<p>   
   <span>Continente</span>
   <select id="select1">
   <option value=""></option>
   </select>
</p>
<p>
   <span>País</span>
   <select id="select2">
   <option value=""></option>
   </select>
</p>
<p>
   <span>Cuidad</span>
   <select id="select3">
   <option value=""></option>
   </select>
</p>
<p>
   <span>Aldea</span>
   <select id="select4">
   <option value=""></option>
   </select>
</p>

<script type="text/javascript" src="hCombos.js"></script>
<script type="text/javascript">
   var combos = new hCombos();
   combos.ids = ['select1', 'select2', 'select3', 'select4'];
   combos.pre = ['1', '1.1', '1.1.3', '1.1.3.2'];
   combos.info = {
      "1": {des: "America",
         values: {
            "1.1": {des: "Argentina",
               values: {
                  "1.1.1": {des: "Ciudad de Argentina 1",
                     values:{
                        "1.1.1.1": {des: "Aldea 1 de la primera cuidad de Argentina"},
                        "1.1.1.2": {des: "Aldea 2 de la primera cuidad de Argentina"},
                        "1.1.1.3": {des: "Aldea 3 de la primera cuidad de Argentina"},
                     }
                  },
                  "1.1.2": {des: "Ciudad de Argentina 2",
                     values:{
                        "1.1.2.1": {des: "Aldea 1 de la segunda cuidad de Argentina"},
                        "1.1.2.2": {des: "Aldea 2 de la segunda cuidad de Argentina"},
                        "1.1.2.3": {des: "Aldea 3 de la segunda cuidad de Argentina"},
                     }
                  },
                  "1.1.3": {des: "Ciudad de Argentina 3",
                     values:{
                        "1.1.3.1": {des: "Aldea 1 de la tercera cuidad de Argentina"},
                        "1.1.3.2": {des: "Aldea 2 de la tercera cuidad de Argentina"},
                        "1.1.3.3": {des: "Aldea 3 de la tercera cuidad de Argentina"},
                     }
                  }
               }
            },
            "1.2": {des: "Honduras",
               values: {
                  "1.2.1": {des: "Ciudad de Honduras 1"},
                  "1.2.2": {des: "Ciudad de Honduras 2"},
                  "1.2.3": {des: "Ciudad de Honduras 3"}
               },
            },
            "1.3": {des: "México",
               values: {
                  "1.3.1": {des: "Cuidad de México 1"},
                  "1.3.2": {des: "Cuidad de México 2"},
                  "1.3.3": {des: "Cuidad de México 3"}
               }
            }
         }
      },
      "2": {des: "Asia",
         values: {
            "2.1": {des: "China",
               values: {
                  "2.1.1": {des: "Ciudad de China 1"},
                  "2.1.2": {des: "Ciudad de China 2"},
                  "2.1.3": {des: "Ciudad de China 3"}
               }
            },
            "2.2": {des: "Japón",
               values: {
                  "2.2.1": {des: "Ciudad de Japón 1"},
                  "2.2.2": {des: "Ciudad de Japón 2"},
                  "2.2.3": {des: "Ciudad de Japón 3"}
               },
            },
            "2.3": {des: "Korea",
               values: {
                  "2.3.1": {des: "Cuidad de Korea 1",
                     values:{
                        "3.2.1.1": {des: "Aldea 1 de la primera cuidad de Korea"},
                        "3.2.1.2": {des: "Aldea 2 de la primera cuidad de Korea"},
                        "3.2.1.3": {des: "Aldea 3 de la primera cuidad de Korea"},
                     }
                  },
                  "2.3.2": {des: "Cuidad de Korea 2",
                     values:{
                        "3.2.1.1": {des: "Aldea 1 de la primera cuidad de Korea"},
                        "3.2.1.2": {des: "Aldea 2 de la primera cuidad de Korea"},
                        "3.2.1.3": {des: "Aldea 3 de la primera cuidad de Korea"},
                     }
                  },
                  "2.3.3": {des: "Cuidad de Korea 3",
                     values:{
                        "3.2.1.1": {des: "Aldea 1 de la primera cuidad de Korea"},
                        "3.2.1.2": {des: "Aldea 2 de la primera cuidad de Korea"},
                        "3.2.1.3": {des: "Aldea 3 de la primera cuidad de Korea"},
                     }
                  }
               }
            }
         }
      },
      "3": {des: "Europa",
         values: {
            "3.1": {des: "Alemania",
               values: {
                  "3.1.1": {des: "Ciudad de Alemania 1"},
                  "3.1.2": {des: "Ciudad de Alemania 2"},
                  "3.1.3": {des: "Ciudad de Alemania 3"}
               }
            },
            "3.2": {des: "España",
               values: {
                  "3.2.1": {des: "Ciudad de España 1"},
                  "3.2.2": {des: "Ciudad de España 2"},
                  "3.2.3": {des: "Ciudad de España 3"}
               },
            },
            "3.3": {des: "Francia",
               values: {
                  "3.3.1": {des: "Cuidad de Francia 1"},
                  "3.3.2": {des: "Cuidad de Francia 2"},
                  "3.3.3": {des: "Cuidad de Francia 3"}
               }
            }
         }
      }
   };
   combos.init();
</script>

</body>
</html>


(hCombos.js)

Código :

function hCombos(){
   this.ids  = [];
   this.info = {};
   this.num  = {};
   this.objs = [];
   this.pre  = [];
   this.ocupado = false;
   
   this.init = function(){
      var clase = this;
      var id, obj;
      for(var n = 0; n < this.ids.length; n++){
         id = this.ids[n];
         this.num[id] = n;
         obj = document.getElementById(id);
         if (n != this.ids.length - 1){
            obj.onchange = function(){
               if(clase.ocupado == false){
                  clase.ocuapo == true;
                  clase.change(this, this.id);
                  clase.ocupado = false;
               }
            };
         }
         this.objs.push(obj);
      }
      this.refreshOpts(0, this.info);
      
      if (this.pre.length > 0){ 
         var combo, options;
         for(var n = 0; n < this.pre.length; n++){
            combo = this.objs[n];
            options = combo.getElementsByTagName("option");
            for(var m = 0; m < options.length; m++){
               if(options[m].value == this.pre[n]){
                  options[m].selected = "selected";
                  if (combo.onchange)   combo.onchange();
               }
            }
         }
      }
      
   };
   
   this.change = function(obj, id){
      var arbol = this.info;
      var numNivel = this.num[id];
      var arbolDes = '';
      var arbolId = '';
      var arbolHijo = {};
      var restantes = 0;

      for (var n = 0; n < this.ids.length; n++){
         arbolId = this.objs[n].value; 
         if(!arbolId){
            restantes = n + 1;
            break;
         }
         arbolDes = arbol[arbolId].des;
         
         if (n == numNivel){
            this.refreshOpts(n + 1, arbol[arbolId].values);
         }
         
         arbol = arbol[arbolId].values;
      }
      if(restantes < this.ids.length)
      for(var n = restantes; n < this.ids.length; n++){
         this.refreshOpts(n, {});
      }
   };
   
   this.refreshOpts = function(nCombo, valores){
      if (!this.objs[nCombo]) return;
      var combo = this.objs[nCombo];
      var preVal = combo.value;
      combo.innerHTML = '';
      
      var opt = this.newOpt('', '');
      combo.appendChild(opt);
      
      for(x in valores){
         opt = this.newOpt(x, valores[x].des);
         combo.appendChild(opt);
      }
   };
   
   this.newOpt = function(value, innerHTML){
      var opt = document.createElement('option');
      opt.value = value;
      opt.innerHTML = innerHTML;
      return opt;
   };
   
};

/* Developed by Herson Salinas, feel free to share */



Parámetros que deben ingresar para que funcione correctamente:


Código :

combos.ids = ['select1', 'select2', 'select3', 'select4'];

  • id: estos son los id de los combobox van según el nivel de anidacion

Código :

combos.pre = ['1', '1.1', '1.1.3', '1.1.3.2'];

  • valores Pre-Seleccionados: estos son las llaves dentro del arbol JSON de los valores que estaran activos por default, pueden omitir esta linea libremente.

Código :

combos.info = {...}


Este es el árbol de datos del cual se extrae la información, como pueden ver en el ejemplo entre más niveles sean, será más anidado y engorroso (para eso fue que creé también la clase en php que lo genera) pero básicamente es un objeto con un valor "des" (descripción que muestra en el combo) y otro valor "values" el cual es un objeto que contiene los subniveles, las llaves de esos subniveles serán la propiedad value que tendrá el combo al ser seleccionado.

Bueno espero que les sea útil y nos vemos en el post donde ampliaré todo esto para que lo puedas manjear desde PHP y poder hacerlo mas dinamico aún generándolo desde una consulta de MySQL.

Archivos del tutorial

Saludos ^^

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

El autor de este artículo ha cerrado los comentarios. Si tienes preguntas o comentarios, puedes hacerlos en el foro

Entra al foro y participa en la discusión

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate