martes, 13 de octubre de 2009

Select dinamicos de Pais/Regiones/Ciudad/Comunas con php y javascript

el ejemplo esta aqui

siempre se pide en todos lados general select anidados, de que si se seleciona x pais el combo de ciudades tiene que llenarse dependiendo del pais.

Aqui hice un ejemplo con php, javascript usando mochikit, y Json.

el codigo es totalmente reutilizable, aspectos importantes:

- En header.php esta la coneccion a la DB.
- Se uso json_encode para formar un arreglo de json por cada fila. esto ya es una funcion nativa en las ultimas versiones de php.
- Se generan elementos html dinamicamente con javascript. usando mochikit.
- Se conectan con mochkit los select, al momento de hacer onchange, mediante signal.

Aqui esta el codigo


<?php require_once ("header.php");


$arregloPaises = array();
$arregloRegiones = array();
$arregloCiudades = array();
$arregloComunas = array();

$query_paises = "select idpais as id, descripcion as nombre from paises";
$query_regiones = "select id as id, descripcion as nombre ,idpais as idpais from regiones";
$query_ciudades = "select id as id, descripcion as nombre ,idregion as idregion from ciudades";
$query_comunas = "select id as id, descripcion as nombre ,idciudad as idciudad from comunas";

$result_paises = mysql_query($query_paises);
$result_regiones = mysql_query($query_regiones);
$result_ciudades = mysql_query($query_ciudades);
$result_comunas = mysql_query($query_comunas);

while ($result_paises && $row = mysql_fetch_object($result_paises))
$arregloPaises[] = $row;
while ($result_regiones && $row = mysql_fetch_object($result_regiones))
$arregloRegiones[] = $row;
while ($result_ciudades && $row = mysql_fetch_object($result_ciudades))
$arregloCiudades[] = $row;
while ($result_comunas && $row = mysql_fetch_object($result_comunas))
$arregloComunas[] = $row;

$paisesJS = json_encode($arregloPaises);
$regionesJS = json_encode($arregloRegiones);
$ciudadesJS = json_encode($arregloCiudades);
$comunasJS = json_encode($arregloComunas);
?>
<html>
<head>
<script src="js/mochikit.js"></script>

<script>
var paises = <?=$paisesJS?>;
var regiones = <?=$regionesJS?>;
var ciudades = <?=$ciudadesJS?>;
var comunas = <?=$comunasJS?>;

function getRegionesByPais(idpais){
var newArreglo = [];
for (var i=0;i<regiones.length;i++)
if (regiones[i].idpais==idpais)
newArreglo.push(regiones[i]);
return newArreglo;
}

function getCiudadesByRegion(idregion){
var newArreglo = [];
for (var i=0;i<ciudades.length;i++)
if (ciudades[i].idregion==idregion)
newArreglo.push(ciudades[i]);
return newArreglo;
}

function getComunasByCiudad(idciudad){
var newArreglo = [];
for (var i=0;i<comunas.length;i++)
if (comunas[i].idciudad==idciudad)
newArreglo.push(comunas[i]);
return newArreglo;
}

function setDataSource(obj,items){
var arreglo = getElementsByTagAndClassName("option",null,obj);
for (var i=0;i<arreglo.length;i++)
removeElement(arreglo[i]);
if (items!=null)
for (var i=0;i<items.length;i++)
appendChildNodes(obj, OPTION({'value':items[i].id},null,items[i].nombre));
}

addLoadEvent(
function(){
setDataSource($('pais'),paises);

connect ($('pais'),"onchange", function (elem){
setDataSource($('region'),getRegionesByPais(elem.target().value));
setDataSource($('ciudad'),null);
setDataSource($('comuna'),null);
}
);
connect ($('region'),"onchange", function (elem){
setDataSource($('ciudad'),getCiudadesByRegion(elem.target().value));
setDataSource($('comuna'),null);
}
);
connect ($('ciudad'),"onchange", function (elem){
setDataSource($('comuna'),getComunasByCiudad(elem.target().value));
}
);
});
</script>
</head>
<body>
<select id="pais" name="pais"></select>
<br>
<select id="region" name="region"/></select>
<br>
<select id="ciudad" name="ciudad"/></select>
<br>
<select id="comuna" name="comuna"/></select>
<br>

</body>
</html>



y la base de datos es la siguiente:


CREATE TABLE `ciudades` (
`ID` int(11) NOT NULL auto_increment,
`DESCRIPCION` varchar(30) default NULL,
`IDREGION` int(11) default NULL,
PRIMARY KEY (`ID`)
) ;

CREATE TABLE `paises` (
`IDPAIS` int(11) NOT NULL auto_increment,
`DESCRIPCION` varchar(30) default NULL,
PRIMARY KEY (`IDPAIS`)
);

CREATE TABLE `regiones` (
`ID` int(11) NOT NULL auto_increment,
`DESCRIPCION` varchar(30) default NULL,
`IDPAIS` int(11) default NULL,
PRIMARY KEY (`ID`)
);

CREATE TABLE `comunas` (
`ID` int(11) NOT NULL auto_increment,
`DESCRIPCION` varchar(30) default NULL,
`IDCIUDAD` int(11) default NULL,
PRIMARY KEY (`ID`)
);


y aqui algunos datos para probar:


INSERT INTO `ciudades` VALUES (1, 'Iquique', 1);
INSERT INTO `ciudades` VALUES (2, 'Antofagasta', 2);
INSERT INTO `ciudades` VALUES (3, 'Copiapo', 3);
INSERT INTO `ciudades` VALUES (4, 'La Serena', 4);
INSERT INTO `ciudades` VALUES (5, 'Valparaiso', 5);
INSERT INTO `ciudades` VALUES (6, 'Rancagua', 6);
INSERT INTO `ciudades` VALUES (7, 'Talca', 7);
INSERT INTO `ciudades` VALUES (8, 'Concepcion', 8);
INSERT INTO `ciudades` VALUES (9, 'Temuco', 9);
INSERT INTO `ciudades` VALUES (10, 'Osorno', 10);
INSERT INTO `ciudades` VALUES (11, 'Aysen', 11);
INSERT INTO `ciudades` VALUES (12, 'Magallanes', 12);
INSERT INTO `ciudades` VALUES (13, 'Santiago', 13);
INSERT INTO `ciudades` VALUES (14, 'Valdivia', 14);
INSERT INTO `ciudades` VALUES (15, 'Arica', 15);
INSERT INTO `ciudades` VALUES (17, 'santiago2', 13);





INSERT INTO `comunas` VALUES (1, 'Alto Hospicio', 1);
INSERT INTO `comunas` VALUES (2, 'Pica', 1);
INSERT INTO `comunas` VALUES (3, 'Taltal', 2);
INSERT INTO `comunas` VALUES (4, 'Mejillones', 2);
INSERT INTO `comunas` VALUES (5, 'Caldera', 3);
INSERT INTO `comunas` VALUES (6, 'Copiapo', 3);
INSERT INTO `comunas` VALUES (8, 'La Serena', 4);
INSERT INTO `comunas` VALUES (9, 'Casablanca', 5);
INSERT INTO `comunas` VALUES (10, 'Quintero', 5);
INSERT INTO `comunas` VALUES (11, 'Rancagua', 6);
INSERT INTO `comunas` VALUES (13, 'Rio Claro', 7);
INSERT INTO `comunas` VALUES (14, 'Constitucion', 7);
INSERT INTO `comunas` VALUES (15, 'Lota', 8);
INSERT INTO `comunas` VALUES (16, 'Coronel', 8);
INSERT INTO `comunas` VALUES (18, 'Temuco', 9);
INSERT INTO `comunas` VALUES (19, 'Rio Negro', 10);
INSERT INTO `comunas` VALUES (20, 'Puyehue', 10);
INSERT INTO `comunas` VALUES (21, 'Guaitecas', 11);
INSERT INTO `comunas` VALUES (22, 'Cisnes', 11);
INSERT INTO `comunas` VALUES (35, 'San Miguel', 13);
INSERT INTO `comunas` VALUES (24, 'Punta Arenas', 12);
INSERT INTO `comunas` VALUES (25, 'Quinta Normal', 13);
INSERT INTO `comunas` VALUES (26, 'Pudahuel', 13);
INSERT INTO `comunas` VALUES (27, 'Santiago', 13);
INSERT INTO `comunas` VALUES (28, 'Renca', 13);
INSERT INTO `comunas` VALUES (29, 'Las Condes', 13);
INSERT INTO `comunas` VALUES (30, 'Providencia', 13);
INSERT INTO `comunas` VALUES (31, 'Paillaco', 14);
INSERT INTO `comunas` VALUES (32, 'Corral', 14);
INSERT INTO `comunas` VALUES (33, 'Camarones', 15);
INSERT INTO `comunas` VALUES (34, 'Arica', 15);





INSERT INTO `paises` VALUES (1, 'Chile', 3);
INSERT INTO `paises` VALUES (3, 'Argentina', 6);
INSERT INTO `paises` VALUES (4, 'Bolivia', 16);
INSERT INTO `paises` VALUES (5, 'Venezuela', 15);
INSERT INTO `paises` VALUES (6, 'Colombia', 11);
INSERT INTO `paises` VALUES (7, 'Japon', 10);
INSERT INTO `paises` VALUES (8, 'Cuba', 12);
INSERT INTO `paises` VALUES (9, 'Mexico', 7);
INSERT INTO `paises` VALUES (10, 'austria', 2);
INSERT INTO `paises` VALUES (12, 'aaaa', NULL);



INSERT INTO `regiones` VALUES (1, 'I region', 1);
INSERT INTO `regiones` VALUES (2, 'II region', 1);
INSERT INTO `regiones` VALUES (3, 'III region', 1);
INSERT INTO `regiones` VALUES (4, 'IV region', 1);
INSERT INTO `regiones` VALUES (5, 'V region', 1);
INSERT INTO `regiones` VALUES (6, 'VI region', 1);
INSERT INTO `regiones` VALUES (7, 'VII region', 1);
INSERT INTO `regiones` VALUES (8, 'VIII region', 1);
INSERT INTO `regiones` VALUES (9, 'IX region', 1);
INSERT INTO `regiones` VALUES (10, 'X region', 1);
INSERT INTO `regiones` VALUES (11, 'XI region', 1);
INSERT INTO `regiones` VALUES (12, 'XII region', 1);
INSERT INTO `regiones` VALUES (13, 'Metropolitana', 1);
INSERT INTO `regiones` VALUES (14, 'XIV region', 1);
INSERT INTO `regiones` VALUES (15, 'XV region', 1);


En resumen, el codigo es bastante chico, usando json, mochikit, nos queda con un html muy limpio, solo conectamos los select al momento de cargar la pagina.


--
Atte.
Victor Hugo Saavedra
http://vhspiceros.blogspot.com

53 comentarios:

  1. Probé el ejemplo http://vhspiceros.googlepages.com/test.htm en mi explorer 8 y no funciona. Hay un error javascript:

    Mensaje: Expected identifier, string or number
    Línea: 42
    Carácter: 75
    Código: 0
    URI: http://vhspiceros.googlepages.com/test.htm

    ResponderEliminar
  2. Gracias lester, ahi ya lo arregle,

    puse en el html
    <select id="pais" name="pais"></select>
    <br>
    <select id="region" name="region"/></select>
    <br>
    <select id="ciudad" name="ciudad"/></select>
    <br>
    <select id="comuna" name="comuna"/></select>
    <br>

    y saque una coma estaba
    appendChildNodes(obj, OPTION({'value':items[i].id,},null,items[i].nombre));

    lo deje asi
    appendChildNodes(obj, OPTION({'value':items[i].id},null,items[i].nombre));

    lo primero es valido,
    maldito IE.

    de nuevo muchas gracias.
    --
    Atte.
    Victor Hugo Saavedra
    http://vhspiceros.blogspot.com

    ResponderEliminar
  3. Hola, podrias agregar el codigo de conexion con el cual esta compuesto el header...
    Desde ya muchas gracias

    ResponderEliminar
  4. require_once ("funcions.php");
    $link = mysql_connect('localhost', 'root', '*******');
    if (!$link) {
    die('Could not connect: ' . mysql_error());
    }
    mysql_select_db("inventario");
    session_start();

    ResponderEliminar
  5. Hola
    Estoy haciendo lo mismo pero con cuidades y colegios, el tema es q yo cree la bd paises y le inserte los registro que incluiste y ademas puse el codigo en php y no me funciona me conecto y todo pero no corre
    no le hice ninguna modificacion al codigo la idea era q me funcionara para luego adaparlo a mis necesidades, en fin
    Si se te ocurre algo lo agradecere

    ResponderEliminar
  6. tienes que modificarlo,

    esto esta hecho para 4, select, ve si tienes bien las consultas sql

    ResponderEliminar
  7. Hola!!... muchas gracias por el codigo!... esta super bueno...

    me ha funcionado todo...
    solo tengo un problema al capturar de la BD nombres con tildes... estos los carga como nulos...
    mira:
    var regiones = [{"id":"1","nombre":null},{"id":"2","nombre":"Antofagasta"},{"id":"3","nombre":"Atacama"},{"id":"4","nombre":"Coquimbo"},{"id":"5","nombre":null},{"id":"7","nombre":"Maule"},{"id":"8","nombre":null},{"id":"9","nombre":null},{"id":"10","nombre":"Los Lagos"},{"id":"11","nombre":null},{"id":"12","nombre":null},{"id":"13","nombre":"Metropolitana de Santiago"},{"id":"14","nombre":null},{"id":"15","nombre":"Arica y Parinacota"},{"id":"6","nombre":null}];

    ojala puedas ayudarme...
    saludos...

    ResponderEliminar
    Respuestas
    1. $conexion = mysqli_connect($db_host, $db_user, $db_pass,$database) or
      die ("No se ha podido conectar al servidor de Base de datos");
      mysqli_set_charset($conexion,'utf8');

      Eliminar
  8. Hola Victor !! tanto tiempo!!

    Soy David Salgado, de Colegio Interactivo.

    Buscando un ejemplo de estos select, llegué a tu block, ja que chico es la internet.

    Voy a probar tu ejemplo.

    Saludos!!, que estes muy bien!!


    David Salgado

    ResponderEliminar
  9. Hola Victor Hugo haber si me puedes ayudar, a mi no me carga ningun select, lo tengo tal cual tu codijo de arriba y tengo datos en la base e incluso hago un $result independiente y si me traer valores, tengra algo que ver el este archivo que no lo tengo "mochikit.js" mi datos de conex son esto:

    $hostname = "localhost";
    $database = "prueba";
    $username = "root";
    $password = "";
    $conex_prueba = mysql_pconnect($hostname, $username, $password);
    mysql_select_db($database, $conex_prueba);

    te agradeceria mucho que me ayudaras.

    Saludos

    ResponderEliminar
  10. Soy de nuevo el Anonimo anterior, despues de largas horas trabajando con el codijo me di cuenta que si me carga los $paisesJS en los arreglos: [{"id":"1","nombre":"Chile"},{"id":"3","nombre":"Argentina"},{"id":"4","nombre":"Bolivia"},......ect.

    Pero no me los carga en los select, me podrian ayudar porfavor.

    saludos

    ResponderEliminar
  11. Muchas Gracias....!!!
    funciona muy bien el codigo...

    Slds Ivan

    ResponderEliminar
  12. Q tal victor hugo, trato de cargar el codigo pero no se que estoy haciendo mal, tengo dos archivos en php:header.php y funcions.php, ya cree la base de datos; veo las listas desplegables mas no me genera nada, por fa si puedes ser un poco mas explicito de como hacer e identificar los diferentes archivos, para que corra el codigo correctamente..

    ResponderEliminar
  13. y como se haria para en vez de ingresar los paises y regiones con insert , extraerlos de una base de datos?

    ResponderEliminar
  14. da lo mismo... los insert solo son para que poblar los datos, pertienentes.. si ya los tienes cargados mejor, y si las tablas se llaman distinto, tienes que cambiar las consultas sql....


    otra cosa importante es que en la pagina... tienes que incluir mochikit, una libreria de javascript.

    ResponderEliminar
  15. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  16. Hola que tal, ami el código no me carga en los select, llevo horas en eso y no logro dar con el porque. Ademas, ¿que es KEY `FK_IDMONEDA` (`IDMONEDA`)?, me da la impresión que es de otra cosa y no por eso me falla el código

    ResponderEliminar
  17. Ingacio , ya arregle el script sql, muchas gracias

    ResponderEliminar
  18. esta como el orto el código... en la tabla país tienes solo para dos datos e intentas ingresar tres datos??? q pasa acá?

    ResponderEliminar
  19. no te entiendo, si tienes mas datos que agregar mas columnas a la tabla. nada mas.

    ResponderEliminar
  20. estimados alguien que me ayude con estos errores
    MochiKit.Base is undefined
    DOM.js()DOM.js (línea 11)
    [Interrumpir en este error] MochiKit.Base._deps('DOM', ['Base']);
    DOM.js (línea 11)
    addLoadEvent is not defined
    [Interrumpir en este error] addLoadEvent(

    ResponderEliminar
  21. que archivo d emochikit bajaste??

    tienes que bajar http://mochi.github.com/mochikit/dist/MochiKit-1.4.2.zip

    y tienes que usar el arhivo que esta en packed/Mochikit/Mochikit.js

    --
    Atte.
    Víctor Hugo Saavedra
    Http://vhspiceros.blogspot.com

    ResponderEliminar
  22. alguieeen que me pueda ayudar! estoy intentando utilizar este codigo en una web de oscommerce.. pero nose como llamar los datos a la base de datos..

    ResponderEliminar
    Respuestas
    1. ups... nunca he utilizado oscommerce young. lamentablemente no te puedo ayudar de mucho.

      por lo generar estas cosas usan un mecanismo especial para obtener los datos desde la base de datos, en realidad no es tan especial usan una clase.

      Eliminar
  23. tego dudas de como llamas a la base de datos.. el oscommmerce tiene llama a un archivo en el head aplication_top.php
    el cual hace la coneccion con la base de datos..
    ahora tengo una duda .. por lo general en oscommerce se definen las tablas
    en un archivo especial..
    y despues se llaman en un select.. algo asi como

    $check_query = tep_db_query("select count(*) as total from " . TABLE_ZONES . " where zone_country_id = '" . (int)$country . "'");

    pero no entiendo que funcion tienen estos parametros

    $arregloPaises = array();

    ResponderEliminar
  24. mira lo que hago es llenar un arreglo posicion por posicion con

    while ($result_comunas && $row = mysql_fetch_object($result_comunas)){
    $arregloComunas[] = $row;
    }
    y despues simplemente le digo que me convierta a un json con json_encode. nada mas es lo mismo que uno hace generalmente, pero uno siempre usa fech_array en vez de fetch_object...


    se entiende??

    ResponderEliminar
  25. ese array no lleva nada dentro? no soy un experto en php.. sorry

    ResponderEliminar
  26. no, no lleva nada, solo se declara como array, y despues cuando se hace $arreglo[] = "algo" se le asigna en una nueva posicion, es decir, le va a agregando un nuevo elemento al arreglo siempre.

    ResponderEliminar
  27. victor.. tengo todo exactamente cmo lo pusiste.. pero no me carga nada en los menus..

    ResponderEliminar
  28. hola
    disculpa quiero saber una cosa en que arte guardas la base de datos porque el header realiza la conexión pero no encuentro nada; si me explicas te agradecería.

    ResponderEliminar
  29. hola Alejandro:

    los datos de region,ciudad y comuna, los guarde directamente en la base de datos, utilice phpmyadmin para crearlos.

    ResponderEliminar
  30. disculpa como puedo poner que en el recuadro los valores por defecto sean algo asi como Selecciona tu Region, por que en el caso de que la region que esta primera es la de la persona la persona no la cambiara y no le mostrara las comunas ni ciudades..

    ResponderEliminar
  31. al parecer ya te funciono entonces, que bueno..


    ami se me ocurre hacerlo con javascript
    appendChildNodes(obj, OPTION({'value':''},null,'Seleccione una region'));

    lo otro seria bastante feo pero también es posible que agregues ese texto en la base de datos.

    ResponderEliminar
  32. buen aporte, pero tengo un problema, no carga ningun elemento al select .. debo copiar algun archivo especial a la carpeta donde puse la pagina? , como lei por ahi copie el archivo mochikit.js pero nada

    ResponderEliminar
  33. Hola victor estoy fascinado con tu script pero encontre una contradicción que no me deja seguir:

    CREATE TABLE `paises` (
    `IDPAIS` int(11) NOT NULL auto_increment,
    `DESCRIPCION` varchar(30) default NULL,
    PRIMARY KEY (`IDPAIS`)
    );

    Esta bien solo 2 campos idpais y descripcion

    INSERT INTO `paises` VALUES (1, 'Chile', 3);
    INSERT INTO `paises` VALUES (3, 'Argentina', 6);
    INSERT INTO `paises` VALUES (4, 'Bolivia', 16)

    Por que los insert tienen 3 campos?

    Por esto no he podido continuar te agradezco tu respuesta desde ya.

    Saludos.

    ResponderEliminar
    Respuestas
    1. Parece que copie y pegue mal no mas.

      Son solo los 2 primeros campos... Mucha Suerte!!!

      Eliminar
  34. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  35. Hola acabo de probar tú código, pero se me cae al momento de querer seleccionar una ciudad no realiza el onchange, existe alguna manera de colocar como selected un texto por ejemplo algo como :

    --Seleccione--


    Esto para cada uno de los select, desde ya muchas gracias por compartir tus conocimientos.


    ResponderEliminar
  36. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  37. hola victor estuve revisando el codigo que nos das y lo aplique funciona correctamete todo solo que yo lo estoy haciendo con articulos que pertenecen a una categoria esta categoria pertenece a un grupo y el grupo pertenece a una empresa en mi caso tengo 4... y en una empresa hay muchos grupos y en un grupo muchas categorias y hay es donde tengo el problema que cuando selecciono la empresa me aparece los grupos de esta empresa listo bn .. pero cuando selecciono un grupo me aparecen en las categorias de todas las empresas que tienen ese mismo codigo de grupo no se como hacer que me recomiendas

    ResponderEliminar
  38. Great weblog right here! Also your site lots up
    very fast! What web host are you the usage of?
    Can I am getting your affiliate link on your host?
    I want my web site loaded up as fast as yours lol

    Feel free to surf to my site Michael Kors Outlet

    ResponderEliminar
  39. Quality posts is the crucial to invite the people to pay
    a visit the website, that's what this website is providing.

    My web-site Abercrombie Bruxelles

    ResponderEliminar
  40. Heya i'm for the first time here. I came across this board and I find It really useful & it helped me out a lot. I hope to give something back and aid others like you helped me.

    Here is my blog post; Cheap Air Max

    ResponderEliminar
  41. Hi, i believe that i saw you visited my site so i
    got here to return the want?.I'm trying to in finding things to improve my site!I guess its adequate to use some of your ideas!!

    Look into my homepage :: Wholesale Jerseys

    ResponderEliminar
  42. This post will assist the internet users
    for setting up new weblog or even a blog from start to end.


    Feel free to surf to my blog :: Cheap Jerseys (http://nysacpr.org)

    ResponderEliminar
  43. Hi, I do think this is an excellent site. I stumbledupon
    it ;) I will come back yet again since I bookmarked it.
    Money and freedom is the best way to change, may you be rich
    and continue to guide other people.

    my homepage ... Sac Louis Vuitton

    ResponderEliminar
  44. Hi there would you mind letting me know which web host you're using? I've loaded your blog in 3 different browsers and I must say this blog loads a
    lot quicker then most. Can you recommend a good internet hosting provider at a reasonable price?

    Thanks a lot, I appreciate it!

    My web-site Michael Kors

    ResponderEliminar
  45. amigo tienes esto mismo con un agregar eliminar y modificar?

    ResponderEliminar
  46. Hola tengo un problemaa me despliega super las regione , provinciass y comunas pero al grabar las comuna en un campo de contactos los graba como codigo Ejempo 123234 : pertenece a providencia
    cuando quiero ver el dato grabado en comuna sale como 123234 y no como nombre comuna

    ResponderEliminar
  47. mi correo es danielpumarino@hotmail.com

    gracias y saludos

    ResponderEliminar
  48. Una buena fuente más completa y disponible desde bower: https://github.com/knxroot/bdcut-cl

    ResponderEliminar
  49. Muchas gracias! Me ha sido muy últil. Bendiciones para tí.

    ResponderEliminar