3/8/11

Ejemplo en AJAX

Ejemplo en AJAX

Realizaremos un primer ejercicio para intentar entender AJAX. Este primer ejercicio contendrá dos combos, un combo que carga los Estados de la República Mexicana y dependiendo del Estado que seleccionemos, nos actualiza un segundo combo que contiene los Municipios de dicho Estado.

Lo primero que debemos hacer es crear en la base de datos 2 tablas, una de Estados y una de Municipios.

La tabla de Estados tendrá el siguiente formato:

Id_estado | nombre_estado
1 Aguascalientes
2 Baja California
3 Baja California Sur
4 Campeche
5 Chiapas
.
.
.
El SQL para la creación de la tabla como su contenido es el siguiente:
CREATE TABLE IF NOT EXISTS `estados` (
  `idestado` int(11) NOT NULL,
  `estado` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`idestado`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `estados` (`idestado`, `estado`) VALUES
(1, 'Aguascalientes'),
(2, 'Baja California'),
(3, 'Baja California Sur'),
(4, 'Campeche'),
(5, 'Chiapas'),
(6, 'Chihuahua'),
(7, 'Coahuila'),
(8, 'Colima'),
(9, 'Distrito Federal'),
(10, 'Durango'),
(11, 'Estado de México'),
(12, 'Guanajuato'),
(13, 'Guerrero'),
(14, 'Hidalgo'),
(15, 'Jalisco'),
(16, 'Michoacán'),
(17, 'Morelos'),
(18, 'Nayarit'),
(19, 'Nuevo León'),
(20, 'Oaxaca'),
(21, 'Puebla'),
(22, 'Querétaro'),
(23, 'Quintana Roo'),
(24, 'San Luis Potosí'),
(25, 'Sinaloa'),
(26, 'Sonora'),
(27, 'Tabasco'),
(28, 'Tamaulipas'),
(29, 'Tlaxcala'),
(30, 'Veracruz'),
(31, 'Yucatán'),
(32, 'Zacatecas');
CREATE TABLE IF NOT EXISTS `municipios` (
  `id_municipio` int(11) NOT NULL AUTO_INCREMENT,
  `nombre_municipio` varchar(100) NOT NULL,
  `estado` int(11) NOT NULL COMMENT 'Id de tabla estados',
  PRIMARY KEY (`id_municipio`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2578 ;

Falta agregar la lista de municipios lo cual es una lista tan larga que será mejor subirla en un archivo y la pongo al final del post.

Lo siguiente será crear la página que contendrá los combos donde se muestren los datos para lo cual creamos un archivo con el nombre comboBox.php y copiamos el siguiente texto:
";
	$listaEdos = devuelveEdos();
	if (count($listaEdos) > 0) {
		for ($i=0;$i".$renglon['estado']."";
		}
	}else{
		echo "";
	}
	echo "
";
}
?>




Ejemplo de combo



		

		

		 
		 



Estoy dando por hecho que sabemos lo básico de PHP, para no entrar en detalles.

La instrucción
include_once 'edosYMun.php';
Nos indica que utilizaremos el archivo edosYMun.php y que se incluirá solamente una vez, más adelante detallaré su contenido.
function cargaEstados()
Indica que crearemos una función que permite cargar los Estados de la República en un combo.
echo " 
que permite la creación de un combo. La propiedad name y id nos va a permitir identificar el combo de cualquier otro.
El evento onChange manda a llamar a una rutina en caso de que el combo cambie de valor, es decir después de seleccionar algún Estado se lanza el evento y ejecuta una función en javascript que tiene por nombre
muestraMunicipios() 
y recibe como parámetro el evento seleccionado.

Aquí es donde entra JavaScript a escena, ya que una vez seleccionado o modificado alguna opción del combo (en este caso un Estado) manda a llamar un evento en JavaScript pasándole el id de la opción seleccionada.
$listaEdos = devuelveEdos();
Manda a llamar a una function declarada en edosYMun.php que devuelve un array con todos los Estados contenido en la tabla Estados.
if (count($listaEdos) > 0) {
En caso de que haya regresado un array con datos, entonces los muestra, si el array está vacío devuelve como el mensaje de que no fue posible conectarse con la Base de datos.
for ($i=0;$i".$renglon['estado']."";
		}
Recorre el arreglo y por cada estado crea una opción del combo, en este caso asigna como id de cada opción el idestado y como el texto de la opción el valor de la columna que tiene el nombre del Estado.

Esta línea es importante para definir el conjunto de caracteres que se van a utilizar en la página, en este caso decimos que dentro del conjunto de caracteres se incluyen acentos y por lo tanto los nombres de los Estados se van a mostrar correctamente.


Le indica a la página que utilizaremos funciones contenidas en el archivo cargaMunicipios.js
		

Carga el combo creado en la función cargaEstados(), por lo tanto no es necesario escribir aquí el código para su creación.

Crea un combo con el nombre municipios y pone como opción un solo valor con el texto: Selecciona una opción.

Este último combo se actualizará dependiendo del Estado seleccionado, es importante el nombre del combo porque con este podremos indicarle al archivo cargaMunicipios.js que cargue contenido en el combo “municipios”.

Ahora el siguiente paso es crear el archivo edosYMun.php que nos servirá para obtener los nombres de los Estados de la Base de datos, así como también obtener los municipios de un Estado en particular.

Para la la creación del archivo edosYMun.php debemos copiar el siguiente código:

".$renglon['nombre_municipio'];
	}
}

  function Conectar()
  {
    if (!($link=mysql_connect("localhost","root",""))){
      echo "Error conectando a la base de datos.";
      exit();
    }
    if (!mysql_select_db("concursos",$link))
    {
      echo "Error seleccionando la base de datos.";
      exit();
    }
    return $link;
  }

	function devuelveEdos()
	{
	 $link=Conectar();
     $arreglo = mysql_query("SELECT * FROM estados",$link);
	 $todo = array();
		while ($fila = mysql_fetch_array($arreglo, MYSQL_ASSOC)){
			$todo[] = $fila;
		}
		return $todo;
	}
Para analizar este archivo vamos a ir ahora de abajo hacia arriba porque es la forma como están declaradas las funciones y seguramente quedará mas claro.
	
function devuelveEdos()
	{
	 $link=Conectar();
     $arreglo = mysql_query("SELECT * FROM estados",$link);
	 $todo = array();
		while ($fila = mysql_fetch_array($arreglo, MYSQL_ASSOC)){
			$todo[] = $fila;
		}
		return $todo;
	}

Como el nombre lo indica, hace una conexión con la base de datos y ejecuta la consulta que selecciona todos los campos o todas las columnas de la tabla ‘estados’. El resultado lo devuelve en un array.

while ($fila = mysql_fetch_array($arreglo, MYSQL_ASSOC)){
Va obteniendo de la table cada uno de los registros para ponerlos en un array pero (MYSQL_ASSOC) conservando los índices asociativos, es decir, con los nombres de los campos.
function Conectar()
  {
    if (!($link=mysql_connect("localhost","root",""))){
      echo "Error conectando a la base de datos.";
      exit();
    }
    if (!mysql_select_db("concursos",$link))
    {
      echo "Error seleccionando la base de datos.";
      exit();
    }
    return $link;
  }
Al función típica para conectarnos a una base de datos usando PHP y MySql, basta con pasarle la dirección a donde nos deseamos conectar, el usuario y contraseña y crear una conexión que podrá servirnos para hacer las consultas a la base.

if (isset($_GET['estado'])){
	$estado = $_GET['estado'];
	$link=Conectar();
    $arreglo = mysql_query("SELECT * FROM municipios WHERE estado = $estado",$link);
	$todo = array();
	  while ($fila = mysql_fetch_array($arreglo, MYSQL_ASSOC)){
		$todo[] = $fila;
	  }
    for ($i=0;$i".$renglon['nombre_municipio'];
	}
}
Si la variable $_GET[‘estado’] tiene algún parámetro entonces se refiere que alguien hizo referencia al archivo pasándole el id de algún Estado, por lo tanto debemos hacer una consulta para obtener los municipios de dicho Estado.

Por lo tanto hacemos la consulta seleccionando todos los campos de la tabla municipios donde el campo Estado sea igual al idEstado que nos pasaron.

Una vez hecha la consulta tendremos un array con todos los elementos, por lo que será necesario crear un Option por cada municipio y que servirá para llenar el Combo de municipios que tenemos en la página principal.

NOTA: Una primera versión colocaba el TAG < option > < / option > y sus propiedades eran el id_municipio y el nombre del municipio, sin embargo esto sólo funcionaba con Firefox y Chrome, pero no jaló con IExplorer por lo que tuve que modificar el código para que funcionara en los 3 Browsers

Esta función me va a regresar
nombre_municipionombre_municipio


header("Content-Type: text/html; charset=iso-8859-1");
Esta línea es importante ya que varios municipios tienen acentos y pueden no mostrarse de forma correcta, cuando se envía a javascript el array con la lista de municipios, se envía con caracteres que no reconoce y por lo tanto aparecen símbolos en lugar de vocales acentuadas, como experimento sería bueno borrar la línea y ver el resultado.

Hasta aquí tenemos una pantalla de presentación con los combos y un archivo php que devuelve lista de Estados o devuelve lista de municipios si le pasamos como parámetro el id del Estado. Necesitamos uno que conecte ambos archivos y ese está en código JavaScript y es el encargado de solicitar información y pasarla a un objeto en particular del archivo de presentación.

Veamos ahora el archivo cargaMunicipios.js
function getHTTPObject(){
  if (window.ActiveXObject) 
	  return new ActiveXObject("Microsoft.XMLHTTP");
  else if (window.XMLHttpRequest) 
	  return new XMLHttpRequest();
  else {
      alert("Tu navegador no soporta AJAX, te recomendamos actualizar tu sistema.");
      return null;
  }
}
 
function muestraMunicipios(idSelectOrigen){
	var selectOrigen=document.getElementById(idSelectOrigen);
	var opcionSeleccionada = selectOrigen.options[selectOrigen.selectedIndex].value;
	var selectDestino=document.getElementById('municipios');
  httpObject = getHTTPObject();
  if (httpObject != null) 
  {
    httpObject.open("GET", "EdosYMun.php?estado="+opcionSeleccionada, true);
    httpObject.onreadystatechange=function() 
	{ 
		if (httpObject.readyState==1)
		{
			selectDestino.length=0;
			var nuevaOpcion=document.createElement("option"); 
			nuevaOpcion.value=0; 
			nuevaOpcion.innerHTML="Cargando...";
			selectDestino.appendChild(nuevaOpcion);
		}
		if (httpObject.readyState==4)
		{
			var cadena = httpObject.responseText;						var pares = cadena.split("<");        
			selectDestino.length=0;               			for (i=1; i");                   				nuevaOpcion.value=muni[0];                        				nuevaOpcion.innerHTML=muni[1];                    				selectDestino.appendChild(nuevaOpcion);           			}
		} 
	}
    httpObject.send(null);    
  }
}
var httpObject = null;
function getHTTPObject(){

Se declara una función que devuelve un objeto XMLHTTP.

XMLHTTP es una clase que puede hacer llamadas o mejor dicho, peticiones al servidor. Una de las ventajas es que estas peticiones las hace y no tiene que esperar a que le contesten, sino que define eventos que se dispararán en el momento en que el servidor tenga los datos solicitados.

La primera versión de la clase XMLHTTP fue desarrollada por Microsoft para el IE 5 por lo que era necesario crearla como un objeto Activex. Por lo tanto para los que tengan el navegador IE 5 o IE 6 deben crear un objeto Activex para poder crear el XMLHTTP.

Los navegadores o browsers recientes pueden crear un objeto XMLHttpRequest incluyendo el IE después de la versión 7

if (window.ActiveXObject) 
	  return new ActiveXObject("Microsoft.XMLHTTP");
  else if (window.XMLHttpRequest) 
	  return new XMLHttpRequest();
  else {
      alert("Tu navegador no soporta AJAX, te recomendamos actualizar tu sistema.");
      return null;
Por lo tanto la función anterior devuelve el objeto XMLHttpRequest si el navegador lo soporta.
function muestraMunicipios(idSelectOrigen){
Esta es la función que mandamos llamar desde el archivo comboBox.php en la parte donde decía onChange=’javaScript:muestraMunicipios(this.id)’
Por lo tanto cuando cambiaba de opción el combo de los Estados se manda a llamar a esta función, ahora veamos que hace.

var selectOrigen=document.getElementById(idSelectOrigen);
Obtiene el componente que sufrió el cambio o dicho de otra manera, obtiene el elemento que mandó llamar a la función.
var opcionSeleccionada=selectOrigen.options[selectOrigen.selectedIndex].value;
Devuelve al opción del combo que el usuario seleccionó, con esto obtenemos el id_estado.
	var selectDestino=document.getElementById('municipios');
Aquí se define el componente que recibirá la información que le vamos a proporcionar más adelante, en este caso el combo que lleva por nombre ‘municipios’.
httpObject = getHTTPObject();
Asignamos a la variable httpObject el objeto que va a servir de enlace con el servidor, ya sea el XMLHTTP o el XMLHttpRequest.

if (httpObject != null) 
  {
    httpObject.open("GET", "edosYMun.php?estado="+opcionSeleccionada, true);
Si el objeto si se pudo crear entonces seguimos con la comunicación con el servidor, en caso contrario pues no hacemos nada más que informar que su browser es un poco antiguo y necesita actualizarlo.

Le indicamos que método vamos a usar, puede ser GET o POST, en este caso es mediante GET.

Le indidamos la ruta del archivo dentro del servidor y le pasamos los parámetros que en este caso es el id del Estado.

Luego le indicamos si va a ser de forma síncrona o asíncrona, con TRUE le decimos que es asíncrona, es decir, no esperamos a que nos conteste, mas bien continuamos con la ejecución del programa.

if (httpObject.readyState==1)
		{
			selectDestino.length=0;
			var nuevaOpcion=document.createElement("option"); 
			nuevaOpcion.value=0; 
			nuevaOpcion.innerHTML="Cargando...";
			selectDestino.appendChild(nuevaOpcion);
		}
El objeto XMLHttpRequest tiene un atributo readyState que puede contener 4 valores:
0 = sin inicializar, 1 = abierto, 2 = cabeceras recibidas, 3 = cargando y 4 = completado

Cuando me dice que el estado del readyState es igual a 1, entonces ya existe comunicación aunque no ha terminado de recibir datos, por lo tanto lo que hago es crear una opción en el combo y ponerle de texto “cargando…”. Al crear un elemento con la cadena “option” JavaScript ya sabe que nos referimos a la etiqueta < option >< / option > y la crea.

Con la instrucción nuevaOpcion.innerHTML="Cargando..."; agrega el texto dentro del tag o del elemento option.

Una vez creado será necesario insertarlo al combo para lo cual se utiliza la instrucción: selectDestino.appendChild(nuevaOpcion);

if (httpObject.readyState==4)
		{
			var cadena = httpObject.responseText;			
var pares = cadena.split("<");        
			selectDestino.length=0;               			
for (i=1; i");                   
				nuevaOpcion.value=muni[0];                        
				nuevaOpcion.innerHTML=muni[1];                    
				selectDestino.appendChild(nuevaOpcion);           
			}
		} 

Cuando el estado del readyState es igual a 4 quiere decir que ha terminado la comunicación con el servidor y puedo revisar que me ha entregado.

var cadena = httpObject.responseText;
Me devuelve el texto o toda la página que consulté para que pueda manipularla, si recordamos la página visitada me devolvía una cadena como la siguiente:
nombre_municipionombre_municipio
Por lo tanto va a ser necesario recorrer todo el texto y buscar los caracteres <> para separar los municipios.
var pares = cadena.split("<");
Con esta instrucción nos devuelve cadenas que están partidas por el carácter < como ese carácter se encuentra antes de cada id_municipio, sabemos que las cadenas van a comenzar con el id_municipio y luego va a tener un carácter > para separar el id_municipio del nombre del municipio por lo tanto tendremos que hacer otro Split.
for (i=1; i");                   
				nuevaOpcion.value=muni[0];                        
				nuevaOpcion.innerHTML=muni[1];                    
				selectDestino.appendChild(nuevaOpcion);           
			}
Recorremos la lista de pares (id_municipio, nombre_municipio) y por cada par que encontremos creamos, un elemento option, partimos el par tomando el primer valor como el valor del elemento option y la cadena como su contenido. Finalmente lo agregamos al combo.
httpObject.send(null);    
Finalmente con esta instrucción envía la petición a la página comboBox.php Finalmente queda listo para visitar la página comboBox.php y seleccionar un Estado y automáticamente se cargará el listado de los municipios sin cargar de nuevo toda la página. Aquí podrás descargar el código de todo lo mostrado: http://www.mediafire.com/?gh43p9icl823gz1

No hay comentarios: