You are on page 1of 119

1 - Qué es AJAX?

AJAX son las siglas de Asynchronous JavaScript And XML. No es un lenguaje de programación sino un conjunto de tecnologías (HTML-JavaScript-CSS-DHTML-PHP/ASP.NET/JSP-XML) que nos permiten hacer páginas de internet más interactivas. La característica fundamental de AJAX es permitir actualizar parte de una página con información que se encuentra en el servidor sin tener que refrescar completamente la página. De modo similar podemos enviar información al servidor. La complejidad se encuentra en que debemos domininar varias tecnologías:       HTML o XHTML CSS JavaScript DHTML Básicamente debemos dominar todos los objetos que proporciona el DOM. XML Para el envío y recepción de los datos entre el cliente y el servidor. PHP o algún otro lenguaje que se ejecute en el servidor (ASP.Net/JSP)

En este curso suponemos que domina las tecnologías mencionadas, en caso de no ser así recomiendo recorrer los cursos de HTML Ya, JavaScript Ya, CSS Ya, PHP Ya y DHTML Ya, luego todo lo nuevo que aparezca lo hiremos explicando lentamente a través de ejemplos.

2 - Ventajas y desventajas de AJAX.
Ventajas 1. 2. 3. 4. 5. 6. Utiliza tecnologías ya existentes. Soportada por la mayoría de los navegadores modernos. Interactividad. El usuario no tiene que esperar hasta que llegen los datos del servidor. Portabilidad (no requiere plug-in como Flash y Applet de Java) Mayor velocidad, esto debido que no hay que retornar toda la página nuevamente. La página se asemeja a una aplicación de escritorio.

Desventajas 1. Se pierde el concepto de volver a la página anterior. 2. Si se guarda en favoritos no necesariamente al visitar nuevamente el sitio se ubique donde nos encontrabamos al grabarla. 3. La existencia de páginas con AJAX y otras sin esta tecnología hace que el usuario se desoriente. 4. Problemas con navegadores antiguos que no implementan esta tecnología. 5. No funciona si el usuario tiene desactivado el JavaScript en su navegador. 6. Requiere programadores que conozcan todas las tecnologías que intervienen en AJAX. 7. Dependiendo de la carga del servidor podemos experimentar tiempos tardíos de respuesta que desconciertan al visitante.

3 - Un ejemplo con AJAX.
Confeccionaremos un ejemplo donde veremos que aparecen muchos conceptos, no se preocupe si no los comprende en su totalidad ya que los mismos se verán en forma detallada a lo largo de este curso. La idea fundamental de este ejercicio es conocer como debemos estructurar nuestras páginas y ver que introduce de nuevo el empleo de AJAX. Confeccionaremos un problema muy sencillo, imaginemos que tenemos una lista de hipervínculos con los distintos signos del horóscopo y queremos que al ser presionado no recargue la página completa sino que se envíe una petición al servidor y el mismo retorne la información de dicho signo, luego se actualice solo el contenido de un div del archivo HTML. Este problema se puede resolver muy fácilmente si refrescamos la página completamente al presionar el hipervínculo, pero nuestro objetivo es actualizar una pequeña parte de la página y más precisamente el div que debe mostrar los datos del signo seleccionado. Si bien nuestra página solo contendrá los hipervínculos a los distintos signos en un caso real la página puede contener muchos otros elementos HTML con imágenes, otros hipervínculos etc. los cuales no deberán sufrir cambios (ni parpadeo) ya que solo se modificará el elemento div respectivo mediante DHTML. Esta actualización parcial de la página tiene muchas ventajas:     Reducimos el ancho de banda requerido al no tener que recuperar toda la página. Agilizamos la actualización de la página. Reducimos el parpadeo de la página. Hacemos más natural la navegación del sitio.

La mayoría de los problemas requieren los siguientes archivos como mínimo: 1. El archivo HTML (es la página que se ve en el navegador) 2. El archivo JS (contiene todas las rutinas JavaScript que permiten actualizar dinámicamente la página HTML (mediante DHTML) y las rutinas que permiten comunicarse con el servidor para el envío y recepción de información. 3. La hoja de estilo, es decir el archivo CSS 4. La página que contiene el script que se ejecuta en el servidor(en nuestro caso emplearemos el lenguaje PHP) Comencemos a presentar los distintos archivos para resolver este problema: pagina1.html <html> <head> <title>Problema</title> <script src="funciones.js" language="JavaScript"></script> <link rel="StyleSheet" href="estilos.css" type="text/css"> </head> <body>

<h1>Signos del horóscopo.</h1> <div id="menu"> <p><a id="enlace1" href="pagina1.php?cod=1">Aries</a></p> <p><a id="enlace2" href="pagina1.php?cod=2">Tauro</a></p> <p><a id="enlace3" href="pagina1.php?cod=3">Geminis</a></p> <p><a id="enlace4" href="pagina1.php?cod=4">Cancer</a></p> <p><a id="enlace5" href="pagina1.php?cod=5">Leo</a></p> <p><a id="enlace6" href="pagina1.php?cod=6">Virgo</a></p> <p><a id="enlace7" href="pagina1.php?cod=7">Libra</a></p> <p><a id="enlace8" href="pagina1.php?cod=8">Escorpio</a></p> <p><a id="enlace9" href="pagina1.php?cod=9">Sagitario</a></p> <p><a id="enlace10" href="pagina1.php?cod=10">Capricornio</a></p> <p><a id="enlace11" href="pagina1.php?cod=11">Acuario</a></p> <p><a id="enlace12" href="pagina1.php?cod=12">Piscis</a></p> </div> <div id="detalles">Seleccione su signo.</div> </body> </html> Esta página contiene HTML puro. Es importante notar que debemos incorporar los dos archivos externos .css y .js mediante los elementos HTML respectivos: <script src="funciones.js" language="JavaScript"></script> <link rel="StyleSheet" href="estilos.css" type="text/css"> La hoja de estilo solo tiene el objetivo de mejorar la presentación en la página de los doce hipervínculos de los signos del horóscopo. Puede probar de eliminar el archivo .css mediante el borrado del elemento link del archivo HTML y el problema debería continuar funcionando, por supuesto con una presentación mucho más pobre. Podemos observar que cada hipervínculo solicita la misma página al servidor pero pasándole como parámetro un valor distinto, con esto podremos detectar en el servidor que signo a elegido el operador. El segundo archivo contiene las reglas de estilo que se definen para el archivo HTML: estilos.css #menu { font-family: Arial; margin:5px; } #menu p { margin:0px; padding:0px; } #menu a { display: block; padding: 3px; width: 160px; background-color: #f7f8e8;

color: #fff. } } function presionEnlace(e) .presionEnlace. padding:5px. text-align:center.false). } No haremos un análisis de estas reglas ya que corresponden al tema 28 del curso de CSS Ya "Creación de un menú vertical configurando las pseudoclases" . addEvent(ob. #menu a:visited { color: #f00.getElementById('enlace'+f). Ahora viene uno de los puntos claves donde debemos prestar más atención.f++) { ob=document. text-decoration: none. function inicializarEventos() { var ob.f<=12. border: 1px dotted #fa0.'click'. margin:5px. } #menu a:link. for(f=1. } #menu a:hover { background-color: #369.'load'. text-align:left. border-width:0.inicializarEventos.border-bottom: 1px solid #eee. Veamos el archivo en su totalidad y expliquemos en forma muy global (recuerde que a lo largo de este curso iremos profundizando todos estos conceptos de comunicación con el servidor): funciones. puede refrescar los conceptos allí. esto se encuentra en las rutinas JavaScript que debemos implementar para comunicarnos con el servidor. } #detalles { background-color:#ffc. además de lo ya conocido de DHTML para añadir elementos HTML en forma dinámica.false).js addEvent(window. font-family:verdana. Inclusive si todavía conoce poco de CSS y no quiere estudiarlo por ahora puede anular el archivo no incorporándolo en la página HTML suprimiento el elemento link.

if(conexion1. var url=window. conexion1.onreadystatechange = procesarEventos.innerHTML = 'Cargando.target.event.event. conexion1.{ if (window..event) { window.readyState == 4) { detalles.send(null).funcion).nomevento. true). return true.attachEvent('on'+nomevento.funcion. } } var conexion1. cargarHoroscopo(url).open("GET".captura) { if (elemento. } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.innerHTML = conexion1. conexion1.srcElement. url.getAttribute('href').getAttribute('href').getElementById("detalles"). } .responseText. cargarHoroscopo(url).'. } function procesarEventos() { var detalles = document. var url=e. } conexion1=crearXMLHttpRequest(). function cargarHoroscopo(url) { if(url=='') { return. } else if (e) { e.returnValue=false..attachEvent) { elemento. } else { detalles.preventDefault().

} } En esta función registramos el evento click para los doce enlaces de los signos del horóscopo.returnValue=false. } function crearXMLHttpRequest() { var xmlHttp=null. for(f=1. return true. La función presión enlace: function presionEnlace(e) { if (window.f<=12.funcion. .getAttribute('href').event) { window.event. if (window. return xmlHttp.addEventListener(nomevento.getElementById('enlace'+f).XMLHTTP"). Lo primero que se ejecuta es la llamada a la función inicializarEventos() inmediatamente luego que la página se a cargado por completo en el navegador: function inicializarEventos() { var ob.'click'.addEventListener) { elemento. difieren por un número al final.captura).else if (elemento. var url=window.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft.f++) { ob=document.srcElement. Recordemos que siempre llamaremos a la función addEvent (que se encuentra codificada en el mismo archivo) para hacer compatible nuestro código con el navegador IE (recordemos que no cumple los estándares referente a eventos). } else return false. Luego dentro de un for rescatamos la referencia a cada enlace y registramos el evento click indicando que se debe llamar a la función presionEnlace. Para facilitar la codificación recordemos que todos tienen casi el mismo nombre.XMLHttpRequest) xmlHttp = new XMLHttpRequest().false). addEvent(ob.presionEnlace. } En este punto si es indispensable haber realizado el curso de DHTML Ya para entender como registramos los eventos para los doce hipervínculos. else if (window.event.

La función recibe como parámetro la url a la que debe hacer la petición de datos. Veamos ahora la función cargarHoroscopo: var conexion1. luego llama a la función cargarHoroscopo pasandole como referencia la url que contiene el hipervínculo. } conexion1=crearXMLHttpRequest() conexion1.onreadystatechange = procesarEventos. conexion1. var url=e. JavaScript. CSS. cargarHoroscopo(url). conexion1. Todo lo comentado hasta acá se estudió en cursos anteriores: HTML. Lo primero que verificamos que el parámetro no llegue vacío. function cargarHoroscopo(url) { if(url=='') { return. DHTML. .preventDefault().send(null). La creación del objeto de la clase XMLHttpRequest se implementa separada en otra función porque depende del navegador que se trate la sintaxis cambia: function crearXMLHttpRequest() { var xmlHttp=null. El siguiente paso es llamar a la función crearXMLHttpRequest que crea y retorna un objeto de la clase XMLHttpRequest (luego veremos que este objeto nos permite comunicarnos con el servidor de forma asincrónica): conexion1=crearXMLHttpRequest() Esta función se encuentra codificada más abajo dentro del mismo archivo y tiene por objetivo retornar un objeto de la clase XMLHttpRequest.open("GET".cargarHoroscopo(url). } } Primero detecta que navegador se trata y procede a desactivar el evento por defecto para el hipervínculo. en caso de estar vacío salimos con el comando return. } else if (e) { e. true).getAttribute('href'). url.target. } Previo a la definición de esta función definimos una variable global llamada conexion1 que será utilizada en esta y la siguiente función.

Por la diferencia en la forma de crear un objeto de la clase XMLHttpRequest hemos movido esta actividad a esta función. } Como podemos observar verificamos si se trata del navegador IE. El tercer parámetro indicamos si se procesarán los datos de forma asíncrona (true) o síncrona (false) Por último nos falta llamar al método send para que comience el proceso: conexion1. en caso afirmativo creamos un objeto de dicha clase: if (window. Seguidamente llamamos al método open que tiene tres parámetros:    Primero el método de envío de datos (GET o POST) Recordemos que si los datos se envían como parámetros (como es nuestro ejemplo) debemos indicar que utilizamos el método GET El segundo parámetro es la url y la página que procesará los datos que le eviemos.send(null). else if (window.if (window.XMLHTTP").ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. . true). conexion1. veremos el código de esta función más adelante.send(null). url. La función retorna la referencia del objeto creado: return xmlHttp. Retornemos a la función cargarHoroscopo y veamos que hacemos con el objeto de la clase XMLHttpRequest que acabamos de crear: conexion1=crearXMLHttpRequest() conexion1. return xmlHttp. Si no se trata del navegador IE verificamos si existe la clase XMLHttpRequest en el objeto window.XMLHttpRequest) xmlHttp = new XMLHttpRequest().XMLHttpRequest) xmlHttp = new XMLHttpRequest().open("GET". La propiedad onreadystatechange se inicializa con la referencia de una función que será la encargada de procesar los datos enviados por el servidor. conexion1.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. en caso afirmativo la creación del objeto XMLHttpRequest es: if (window.onreadystatechange = procesarEventos.XMLHTTP").

. solidaridad. Interactivo.". de carácter. en nuestro caso empleamos el lenguaje PHP (tener en cuenta que podemos emplear otro lenguaje de servidor para esto) Veamos el código de esta página: if ($_REQUEST['cod']==1) echo "<strong>Aries:</strong> Hoy los cambios serán físicos. íntimos. luego mediante el método responseText recuperamos la información enviada por el servidor.responseText. Pero todavía nos queda la página que contiene el programa en el servidor. Cargado. } else { detalles. if ($_REQUEST['cod']==2) echo "<strong>Tauro:</strong> Hoy los cambios serán privados.'.Nos queda explicar la función procesarEventos que se ejecuta cada vez que el objeto conexion1 de la clase XMLHttpRequest cambia de estado. Luego cualquier otro valor que contenga la propiedad readyState mostramos dentro del div el mensaje 'cargando. o de ayuda a los demás.innerHTML = conexion1.. Es seguro que muchas dudas han surgido de este primer pantallazo de AJAX. Cargando. Para conocer el estado del objeto debemos acceder a la propiedad readyState que almacena alguno de los cinco valores que enunciamos. Tu cónyuge puede aportar buen status a tu vida o apoyo a .readyState == 4) { detalles. Tengamos en cuenta que los estados posibles de este objeto son:      0 1 2 3 4 No inicializado. Nuestra función procesarEventos es: function procesarEventos() { var detalles = document. Ayuda. } } Decíamos que cuando la propiedad readyState almacena 4 significa que todos los datos han llegado desde el servidor..innerHTML = 'Cargando.getElementById("detalles"). Asuntos en lugares de retiro.'. pero no se preocupe a medida que avancemos en el curso se irán aclarando e internalizando. Período en donde considerarás unirte a agrupaciones de beneficencia. Completado. if(conexion1. personales. Te sentirás impulsivo y tomarás iniciativas. Recuerdos..

Experiencias diversas con compañeros. if ($_REQUEST['cod']==5) echo "<strong>Leo:</strong> Este día los estudios.".". Hay karma de prueba durante este período en tu parte psicológica. if ($_REQUEST['cod']==9) echo "<strong>Sagitario:</strong> Durante este día se vivirán cambios en relación a los noviazgos o a los hijos. diversiones y salidas.tu profesión. juicios o herencias. generándose algunos replanteos. Durante este período tendrás muchos recursos para ganar dinero. Deseos difíciles de controlar.".". Período de encuentros con personas o situaciones que te impresionan. con la convivencia y con el padre.".". temas legales. El karma de responsabilidad de estos momentos te acercará al mundo de lo desconocido. Mucha energía sexual y fuerza emocional. Asuntos relativos al carácter en la convivencia.". con la gente o el público. Ellos serán lo más importante del día. Pensamientos. if ($_REQUEST['cod']==8) echo "<strong>Escorpio:</strong> Hoy todo asunto tiene que ver con temas de trabajo y de salud. ilusiones. if ($_REQUEST['cod']==7) echo "<strong>Libra:</strong> Hoy todo asunto tiene que ver con tu pareja. if ($_REQUEST['cod']==6) echo "<strong>Virgo:</strong> Para este día toma importancia tu vida sexual. actividad.". Actividad laboral agradable. if ($_REQUEST['cod']==11) echo "<strong>Acuario:</strong> Hoy todo asunto tiene que ver con el entorno inmediato. Vivencias kármicas de la época te vuelven responsable tomando decisiones. Presta atención a ambos. if ($_REQUEST['cod']==4) echo "<strong>Cancer:</strong> Este día la profesión y las relaciones con superiores y con tu madre serán de importancia. Actividad en relación a estos temas. actividades con ellos. Actividades vocacionales artísticas. mucha madurez y contacto con el más allá. Ganancias a través de especulaciones o del juego. hermanos y . reuniones. if ($_REQUEST['cod']==3) echo "<strong>Géminis:</strong> Los asuntos de hoy tienen que ver con las amistades. if ($_REQUEST['cod']==10) echo "<strong>Capricornio:</strong> Los cambios del día tienen que ver con tu hogar. Momentos positivos con compañeros de trabajo. Experiencias extrañas. Creatividad. Día esperanzado. también con socios. los viajes. religión y filosofía también.". tal vez miedos. el extranjero y la espiritualidad serán lo importante.

si tiene un 2 generamos un texto referente al signo Tauro y así sucesivamente. if ($_REQUEST['cod']==12) echo "<strong>Piscis:</strong> Durante este día se vivirán cambios en la economía. Hasta acá el primer problema de AJAX.css" type="text/css"> </head> <body> <h1>Signos del horóscopo. Momentos de gran fuerza y decisión profesionales. Como debemos recargar la página y actualizar en el servidor los datos del signo del horóscopo seleccionado confeccionaremos solo una página php. 4 . Body etc. los viajes cortos o traslados frecuentes. con la comunicación. El hablar y trasladarse será importante hoy. Hay que tener en cuenta que no se estará enviando una página HTML completa.". movimientos en los ingresos. por eso no tiene los elementos Head. Volveremos a confeccionar el mismo problema que muestra una lista de hipervínculos con los distintos signos del horóscopo. negocios. pero por simplicidad hemos dispuesto estos 12 if y generado el texto respectivo. pagina1. Veremos más adelante problemas que acceden a bases de datos. buscarás el liderazgo.vecinos. ?> Mediante el vector asociativo $_REQUEST recuperamos el valor del parámetro cod y mediante una serie de if verificamos si almacena el valor 1 procedemos a generar un texto referente al signo Aries.". Debe quedar claro que los datos se podrían haber rescatado perfectamente de una base de datos. Mentalidad e ideas activas.El mismo ejemplo sin AJAX.</h1> . Le recomiendo pasar a la sección de "Problemas Resueltos" y ejecutar este ejercicio. es decir recargaremos la página completamente al presionar alguno de los hipervínculos. sino es más bien un archivo de texto que luego será añadido en forma dinámica al div de la página HTML. valores. releer nuevamente estos conceptos y tratar de hacer modificaciones sencillas al problema. a diferencia del problema expuesta en el concepto anterior ahora no emplearemos AJAX.php <html> <head> <title>Problema</title> <link rel="StyleSheet" href="estilos.

php?cod=10">Capricornio</a></p> <p><a id="enlace11" href="pagina1.". de carácter. reuniones. personales.php?cod=8">Escorpio</a></p> <p><a id="enlace9" href="pagina1.". el extranjero y la espiritualidad serán lo importante. Ayuda.php?cod=9">Sagitario</a></p> <p><a id="enlace10" href="pagina1. Actividad en relación a estos temas. if ($_REQUEST['cod']==5) echo "<strong>Leo:</strong> Este día los estudios. Ganancias a través de especulaciones o del juego. ilusiones. Pensamientos.php?cod=12">Piscis</a></p> </div> <div id="detalles"> <?php if (!isset($_REQUEST['cod'])) echo "Seleccione su signo. Actividad laboral agradable. Momentos positivos con compañeros de trabajo. generándose algunos replanteos. Día esperanzado.php?cod=3">Geminis</a></p> <p><a id="enlace4" href="pagina1. religión y filosofía también. o de ayuda a los demás.php?cod=11">Acuario</a></p> <p><a id="enlace12" href="pagina1. Deseos difíciles de controlar. Tu cónyuge puede aportar buen status a tu vida o apoyo a tu profesión. if ($_REQUEST['cod']==3) echo "<strong>Géminis:</strong> Los asuntos de hoy tienen que ver con las amistades. Período en donde considerarás unirte a agrupaciones de beneficencia. Vivencias kármicas de la época te vuelven responsable tomando decisiones. Mucha energía sexual y fuerza emocional.php?cod=6">Virgo</a></p> <p><a id="enlace7" href="pagina1. if ($_REQUEST['cod']==8) .". también con socios. Recuerdos.". if ($_REQUEST['cod']==6) echo "<strong>Virgo:</strong> Para este día toma importancia tu vida sexual. Ellos serán lo más importante del día. con la gente o el público. Asuntos en lugares de retiro. íntimos. if ($_REQUEST['cod']==1) echo "<strong>Aries:</strong> Hoy los cambios serán físicos. if ($_REQUEST['cod']==2) echo "<strong>Tauro:</strong> Hoy los cambios serán privados.php?cod=1">Aries</a></p> <p><a id="enlace2" href="pagina1.php?cod=7">Libra</a></p> <p><a id="enlace8" href="pagina1. Hay karma de prueba durante este período en tu parte psicológica.". if ($_REQUEST['cod']==7) echo "<strong>Libra:</strong> Hoy todo asunto tiene que ver con tu pareja.<div id="menu"> <p><a id="enlace1" href="pagina1.". Actividades vocacionales artísticas.". if ($_REQUEST['cod']==4) echo "<strong>Cancer:</strong> Este día la profesión y las relaciones con superiores y con tu madre serán de importancia.php?cod=5">Leo</a></p> <p><a id="enlace6" href="pagina1. temas legales. los viajes.".php?cod=4">Cancer</a></p> <p><a id="enlace5" href="pagina1. tal vez miedos.php?cod=2">Tauro</a></p> <p><a id="enlace3" href="pagina1. solidaridad. Te sentirás impulsivo y tomarás iniciativas. actividades con ellos. juicios o herencias. Experiencias extrañas.

también evitamos la recarga completa de la página (imaginemos un sitio que contiene muchos elementos el redibujado es lento y engorroso) . Durante este período tendrás muchos recursos para ganar dinero. if ($_REQUEST['cod']==9) echo "<strong>Sagitario:</strong> Durante este día se vivirán cambios en relación a los noviazgos o a los hijos. los viajes cortos o traslados frecuentes. Momentos de gran fuerza y decisión profesionales. o de ayuda a los demás. Presta atención a ambos.echo "<strong>Escorpio:</strong> Hoy todo asunto tiene que ver con temas de trabajo y de salud. negocios.". Asuntos relativos al carácter en la convivencia. Período de encuentros con personas o situaciones que te impresionan. movimientos en los ingresos. El hablar y trasladarse será importante hoy. valores. diversiones y salidas. de carácter. if ($_REQUEST['cod']==12) echo "<strong>Piscis:</strong> Durante este día se vivirán cambios en la economía.". actividad. Te sentirás impulsivo y tomarás iniciativas. personales. if ($_REQUEST['cod']==10) echo "<strong>Capricornio:</strong> Los cambios del día tienen que ver con tu hogar.".". ?> </div> </body> </html> Como podemos observar los hipervínculos llaman a la misma página: href="pagina1. hermanos y vecinos.".". Si comparamos este ejemplo con el anterior veremos que utilizar AJAX reduce la cantidad de información que pedimos al servidor. con la convivencia y con el padre. Mentalidad e ideas activas. con la comunicación. if ($_REQUEST['cod']==11) echo "<strong>Acuario:</strong> Hoy todo asunto tiene que ver con el entorno inmediato. buscarás el liderazgo. mucha madurez y contacto con el más allá.". Período en donde considerarás unirte a agrupaciones de beneficencia. En caso de no llegar parámetros a la página (normalmente la primer vez que cargamos la página) el primer if se verifica verdadero: if (!isset($_REQUEST['cod'])) echo "Seleccione su signo. Creatividad.php?cod=1">Aries</a></p> Luego el código PHP que se ejecuta en el servidor verifica el valor que llega como parámetro y muestra el detalle del signo del horóscopo seleccionado: if ($_REQUEST['cod']==1) echo "<strong>Aries:</strong> Hoy los cambios serán físicos. Experiencias diversas con compañeros. El karma de responsabilidad de estos momentos te acercará al mundo de lo desconocido.

color: #fff. margin:5px. Este objeto nos permite enviar y recibir información en formato XML y en general en cualquier formato (como vimos en el ejercicio anterior retornando un trozo de archivo HTML) La creación de un objeto de esta clase varía si se trata del Internet Explorer de Microsoft. border-width:0. padding: 3px. } #menu p { margin:0px. width: 160px. } #menu a:link.ActiveXObject) .Objeto XMLHttpRequest El objeto XMLHttpRequest es un elemento fundamental para la comunicación asincrónica con el servidor. } #detalles { background-color:#ffc. text-align:left. font-family:verdana. margin:5px.La hoja de estilo no tiene cambios con respecto al problema anterior: #menu { font-family: Arial. } #menu a:hover { background-color: #369. text-decoration: none. border-bottom: 1px solid #eee. } #menu a { display: block. #menu a:visited { color: #f00. padding:5px. border: 1px dotted #fa0. ya que este no lo incorpora en JavaScript sino que se trata de una ActiveX: if (window. } 5 . background-color: #f7f8e8. padding:0px. text-align:center.

if (window. readyState Almacena el estado del requerimiento hecho al servidor.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. } Es decir la función crearXMLHttpRequest se encargará de retornarnos un objeto de la clase XMLHttpRequest. luego de haber hecho una petición.XMLHTTP").XMLHttpRequest) xmlHttp = new XMLHttpRequest().XMLHTTP").   Los métodos principales del objeto XMLHttpRequest son:   open Abre un requerimiento HTTP al servidor. send Envía el requerimiento al servidor.xmlHttp = new ActiveXObject("Microsoft. En cambio en FireFox y otros navegadores lo incorpora JavaScript y procedemos para su creación de la siguiente manera: if (window. pudiendo ser: o 0 No inicializado (el método open no a sido llamado) o 1 Cargando (se llamó al método open) o 2 Cargado (se llamó al método send y ya tenemos la cabecera de la petición HTTP y el status) o 3 Interactivo (la propiedad responseText tiene datos parciales) o 4 Completado (la propiedad responseText tiene todos los datos pedidos al servidor) responseText Almacena el string devuelto por el servidor. else if (window. Como hemos visto en el problema anterior siempre implementaremos una función que nos retorne un objeto XMLHttpRequest haciendo transparente el proceso en cuanto a navegador donde se esté ejecutando: function crearXMLHttpRequest() { var xmlHttp=null.XMLHttpRequest) xmlHttp = new XMLHttpRequest(). responseXML Similar a la anterior (responseText) con la diferencia que el string devuelto por el servidor se encuentra en formato XML. Las propiedades principales del objeto XMLHttpRequest son:   onreadystatechange Almacena el nombre de la función que se ejecutará cuando el objeto XMLHttpRequest cambie de estado. . Confeccionaremos otro problema para fijar conceptos vistos hasta el momento. return xmlHttp.

jpg" alt="cuadro sobre geometria generativa"> </p> Nombre:<input type="text" id="nombre" size="20"><br> Voto:<select id="voto"> <option value="0" selected>seleccione</option> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> <option value="4">4</option> <option value="5">5</option> <option value="6">6</option> <option value="7">7</option> <option value="8">8</option> <option value="9">9</option> <option value="10">10</option> </select><br> <input type="button" id="boton1" value="votar"> <div id="resultados"></div> </body> </html> Lo primero que podemos observar es que no utilizaremos una hoja de estilo para reducir la complejidad del problema y concentrarnos en la lógica.. No definimos la propiedad name ya que no se enviarán los datos por medio de formulario./foto1.Confeccionar una página que muestre una imagen y permita calificarla con un valor entre 1 y 10. Luego al presionar un botón enviar el valor seleccionado utilizando el objeto XMLHttpRequest al servidor donde almacenaremos en un archivo de texto el nombre del visitante y el puntaje. esta es de suma importancia para poder accederla desde JavaScript. Si vemos utilizamos controles de tipo input. Disponer de un control de tipo select para seleccionar el valor. select y button. Actualizaremos la página HTML con todos los nombres y votos hasta el momento. Permitir ingresar el nombre del visitante. Esto se debe a que los datos ingresados se enviarán en forma asíncrona mediante el objeto XMLHttpRequest. Retornar luego todos los votos hasta el momento.html <html> <head> <title>Problema</title> <script src="funciones. Otro punto a destacar que a cada control le definimos la propiedad id. pero no disponemos ningún formulario. Nuestro archivo con las funciones JavaScript es: . El archivo HTML es: pagina1.js" language="JavaScript"></script> </head> <body> <h1>Vote esta foto</h1> <p> <img src=".

conexion1.captura) { if (elemento.innerHTML = conexion1.send(null).nom) { conexion1=crearXMLHttpRequest().getElementById("resultados").js addEvent(window.ob2. } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.responseText.captura). } function presionBoton(e) { var ob1=document..getElementById('boton1').false).value). } else { resultados. conexion1.attachEvent('on'+nomevento. .inicializarEventos.attachEvent) { elemento.funcion).addEventListener(nomevento.php?puntaje='+voto+'&nombre='+nom.funcion.getElementById('nombre'). if(conexion1.innerHTML = 'Cargando. conexion1. cargarVoto(ob1. function inicializarEventos() { var ob=document..onreadystatechange = procesarEventos.open('GET'.'pagina1. } var conexion1.'load'.false).nomevento.presionBoton. return true. function cargarVoto(voto.addEventListener) { elemento. true).getElementById('voto'). } else if (elemento. } function procesarEventos() { var resultados = document.funcion.'.value.funciones. var ob2=document.'click'.readyState == 4) { resultados. addEvent(ob.

cargarVoto(ob1. if (window.return true. } else return false.'click'. Llamamos finalmente a la función cargarVoto: function presionBoton(e) { var ob1=document. Por último inicializamos la propiedad onreadystatechange y llamamos a los métodos open y send.'load'.onreadystatechange = procesarEventos.getElementById('boton1'). } Como podemos observar tiene mucho en común con el primer ejemplo de AJAX que habíamos desarrollado. donde obtenemos la referencia a los dos controles (select y text) que tienen almacenados los valores.value).false). .ActiveXObject) xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"). } Cuando se presiona el botón se dispara la función presionBoton. seguidamente llama a la función crearXMLHttpRequest. function cargarVoto(voto.ob2. addEvent(ob.value. var ob2=document.nom) { conexion1=crearXMLHttpRequest() conexion1. } function crearXMLHttpRequest() { var xmlHttp=null. En el método open pasamos los dos datos en la cabecera de la petición de página.getElementById('nombre'). return xmlHttp. else if (window. Lo primero que hacemos es inicializar el evento load con la función inicializarEventos. } La función cargarVoto recibe como parámetro el valor del voto y el nombre del visitante.inicializarEventos.getElementById('voto').presionBoton.XMLHttpRequest) xmlHttp = new XMLHttpRequest().false). var conexion1. function inicializarEventos() { var ob=document. en esta inicializamos el evento click del único botón que contiene la página: addEvent(window.

php?puntaje='+voto+'&nombre='+nom..innerHTML = conexion1."Voto:". es decir no borramos los votos existentes (puede probar de cambiar "a" de append por "w" que crea el archivo): $ar=fopen("puntaje. ?> Lo primero que hacemos es abrir el archivo para agregar datos."Nombre:".open('GET'.'pagina1.. fputs($ar. } } El archivo PHP que se ejecuta en el servidor es el siguiente: pagina1. Luego recuperamos los parámetros que llegan a la página y los grabamos: fputs($ar. que cuando la propiedad readyState del objeto XMLHttpRequest tiene un valor 4 (proceso completado) recupera el valor de la propiedad responseText con la información que se retornó desde el servidor: function procesarEventos() { var resultados = document."Nombre:"."a") or die("No se pudo abrir el archivo"). $ar=fopen("puntaje."<br>")."<br>"). true).$_REQUEST['nombre'].'.$_REQUEST['nombre']. } Nos queda la función procesarEventos.txt".send(null)."a") or die("No se pudo abrir el archivo"). fputs($ar. fputs($ar. } fclose($ar). fclose($ar).txt".readyState == 4) { resultados.responseText."r") or die("No se pudo abrir el archivo").php <?php header('Content-Type: text/html.$_REQUEST['puntaje']."Voto:".innerHTML = 'Cargando. $ar=fopen("puntaje. } else { resultados. echo $linea. .txt". charset=ISO-8859-1')."<br><br>"). while (!feof($ar)) { $linea=fgets($ar).$_REQUEST['puntaje'].getElementById("resultados").conexion1. if(conexion1."<br><br>"). conexion1.

La diferencia es que la calificación será por medio de una lista de hipervínculos del 1 al 10. luego un igual y el valor del parámetro.php?puntaje='+voto+'&nombre='+nom.Pasando datos al servidor por el método GET. En caso de haber más de un parámetro debemos separarlos mediante el caracter ampersand. El archivo HTML es (pagina1. Además haremos que la barra de selección de la calificación cambie de color cuando ingresamos con el mouse.Cerramos y abrimos nuevamente el archivo.'pagina1.open('GET'. Seguido al nombre de la página debe ir el signo de interrogación. En este ejemplo vemos como indicamos que el envío de los datos se hace por el método GET. es decir que nos permita calificar una foto con un valor de 1 al 10.html): <html> . 6 . true). Por último el tercer parámetro del método open normalmente se pasa el valor true indicando que el requerimiento de la página es asíncrona (esto permite al visitante continuar interactuando con la página sin que se congele hasta llegar la solicitud) Confeccionaremos un problema similar al anterior. } Con este segundo ejemplo debemos poder identificar que partes son comunes al problema anterior. Para indicar cual es el método de envío de los datos al servidor lo hacemos en el primer parámetro del método open del objeto XMLHttpRequest: conexion1. el nombre del parámetro. Si lo hacemos de esta forma tenemos que tener mucho cuidado en la codificación del segundo parámetro del método open donde indicamos el nombre de la página a pedir.txt". pero ahora con el objetivo de leerlo: fclose($ar). Veremos que la mayor dificultad se encuentra en la codificación de esta última característica más que en la comunicación asincrónica."r") or die("No se pudo abrir el archivo"). echo $linea. Por último generamos el archivo a retornar al navegador: while (!feof($ar)) { $linea=fgets($ar). $ar=fopen("puntaje.

voto { padding:0px.voto a { float:left.css" type="text/css"> </head> <body> <h1>Vote esta foto</h1> <p> <img src=".php?voto=2">2</a></li> <li><a href="pagina1./foto1.<head> <title>Problema</title> <script src="funciones.php?voto=1">1</a></li> <li><a href="pagina1.php?voto=4">4</a></li> <li><a href="pagina1./foto1.php?voto=8">8</a></li> <li><a href="pagina1.jpg" alt="cuadro sobre geometria generativa"> Para no complicar más el problema el archivo de resultados se almacena en un archivo de texto llamado votos.txt (al presionar el hipervínculo procedemos a mostrarlo en el navegador.txt">Ver resultados</a> </body> </html> La foto se encuentra en el directorio inmediatamente superior por eso indicamos el .php?voto=3">3</a></li> La hoja de estilo queda definida como sigue (estilos.php?voto=1">1</a></li> <li><a href="pagina1.php?voto=7">7</a></li> <li><a href="pagina1.php?voto=10">10</a></li> </ul> <br> <div id="resultados"></div> <a href="votos..php?voto=2">2</a></li> <li><a href="pagina1.php?voto=5">5</a></li> <li><a href="pagina1.txt">Ver resultados</a> Cada hipervínculo pasa como parámetro la calificación respectiva: <li><a href="pagina1..jpg" alt="cuadro sobre geometria generativa"> </p> <ul class="voto" id="votofoto1"> <li><a href="pagina1.php?voto=3">3</a></li> <li><a href="pagina1. esto nos podrá permitir verificar si realmente el voto se registró en el servidor): <a href="votos. } .css): .php?voto=9">9</a></li> <li><a href="pagina1./ : <img src=". .php?voto=6">6</a></li> <li><a href="pagina1..js" language="JavaScript"></script> <link rel="StyleSheet" href="estilos.

f++) { vec[f].false).false). var vec=ob.f<vec2.salir.js: addEvent(window. border-right:1px solid white. var vec2=ref. font-size:13px. color:#f00.firstChild.firstChild.getElementsByTagName('li').nodeValue.style.style. if (window. for(f=0.'mouseout'.length. vec[f].false). var ob=document. for(f=0.presionBoton.'mouseover'. } Como la lista de hipervínculos los queremos todos en la misma línea inicializamos la propiedad display con el valor inline: . var vec= ref.srcElement. } Luego donde se encuentra la complejidad mayor es en funciones. text-align:center.f<ref. } .width:15px.voto li { display:inline. addEvent(vec[f].'load'.getElementById('votofoto1').getElementsByTagName('a').getElementsByTagName('li').getElementById('votofoto1').voto li { display:inline. else if (e) ref=e. } .false).target.'click'.firstChild. text-decoration:none.background='#f00'.color='#fff'.event) ref=window. function inicializarEventos() { var ref=document. } } function entrar(e) { var ref. addEvent(vec2[f].event.inicializarEventos.entrar. background-color:#f7f8e8.f++) { addEvent(vec[f].

else if (e) ref=e.'pagina1. var aleatorio=Math.send(null).background='#f7f8e8'.getElementById('votofoto1'). } } function presionBoton(e) { var ref.f++) { vec[f].php?voto='+voto+"&aleatorio="+aleatorio.srcElement. var ob=document.f<ref. } var conexion1.onreadystatechange = procesarEventos. var vec=ob.srcElement.event.nodeValue).color='#f00'. if(conexion1.firstChild. true).style.target. for(f=0. conexion1.returnValue=false.open('GET'. if (window. } cargarVoto(ref. ref=e.getElementById("resultados").firstChild.readyState == 4) .firstChild.event. if (window. function cargarVoto(voto) { conexion1=crearXMLHttpRequest().firstChild.style.event) ref=window.event) { window. } else if (e) { e. conexion1. } function procesarEventos() { var resultados = document.random().target.nodeValue. ref=window.} function salir(e) { var ref. vec[f].getElementsByTagName('li').preventDefault(). conexion1.event.

funcion.addEventListener) { elemento.XMLHttpRequest) xmlHttp = new XMLHttpRequest(). Luego obtenemos a partir de la referencia de dicho div todos los elementos li (list item) y a (anchor): var vec= ref.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. return true.getElementsByTagName('li'). return true.attachEvent) { elemento.funcion. } else if (elemento.{ resultados.XMLHTTP"). } function crearXMLHttpRequest() { var xmlHttp=null.'. return xmlHttp.'. } else return false. } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.funcion). } else { resultados..nomevento..addEventListener(nomevento. .innerHTML = 'Gracias.captura) { if (elemento.attachEvent('on'+nomevento. if (window.innerHTML = 'Procesando.getElementById('votofoto1').captura). } La primera función que se ejecuta cuando se termina de cargar por completo la página es inicializarEventos: Obtenemos la referencia al div que contiene la foto: var ref=document. else if (window.

'click'.var vec2=ref.getElementById('votofoto1'). } } La función presionBoton se ejecuta cuando alguno de los elementos a (anchor) es presionado: .f++) { vec[f].target. addEvent(vec2[f]. a los elementos de tipo li le definimos los eventos mouseover y mouseout. luego a los elementos a le definimos el evento click: for(f=0.getElementsByTagName('a'). if (window.color='#f00'.style.firstChild.presionBoton.'mouseover'.f<ref. for(f=0. var ob=document.f++) { addEvent(vec[f].style.background='#f00'. else if (e) ref=e.color='#fff'.entrar.firstChild.false).false).nodeValue.getElementsByTagName('li'). else if (e) ref=e.srcElement.length.event) ref=window.f<vec2.style.nodeValue. } La función entrar se ejecuta cuando la flecha del mouse se dispone dentro de algún elemento de la lista. Luego dentro de un for cambiamos el color de todos los elementos menores e incluyendo al que emitió el evento: function entrar(e) { var ref.f<ref.'mouseout'. var vec=ob. var vec=ob.firstChild. if (window. var ob=document.target. vec[f].event.false). addEvent(vec[f].f++) { vec[f].srcElement. vec[f].event. Pasamos a la asignación de eventos a estos elementos dentro de un for.firstChild. for(f=0. } } El algoritmo es similar cuando sacamos la flecha del mouse de un elemento de tipo li: function salir(e) { var ref.firstChild.event) ref=window.getElementById('votofoto1').style.salir.getElementsByTagName('li').background='#f7f8e8'.firstChild.

onreadystatechange = procesarEventos. conexion1.'pagina1.open('GET'.returnValue=false). } else if (e) { e. Procedemos luego a llamar a la función cargarVoto pasando como referencia el valor contenido el el elemento "a".php?voto='+voto+"&aleatorio="+aleatorio. } cargarVoto(ref.event. en este caso es 'GET'. conexion1.target.'pagina1. conexion1. Esto es necesario si el navegador está configurado que recupere las páginas del cache. ref=e. Ahora llamamos a la función open del objeto XMLHttpRequest indicando: var aleatorio=Math. true).php?voto='+voto+"&aleatorio="+aleatorio.event) { window.nodeValue). true).srcElement. Veamos ahora la función cargarVoto: var conexion1.event.random().open('GET'.random(). El método de conexión utilizado. Inicializamos la propiedad onreadystatechage con el nombre de la función que se disparará cada vez que el objeto XMLHttpRequest cambie de estado. más precisamente el que seleccionó el operador) El dato a enviar se llama voto y almacena el contenido de la variable voto que llega como parámetro a esta función.function presionBoton(e) { var ref.preventDefault().event.returnValue=false. } Creamos un objeto de la clase XMLHttpRequest llamando a la función crearXMLHttpRequest(). if (window. ref=window.preventDefault() o en su defecto si nos encontramos con el navegador IE inicializamos la propiedad returnValue con false (window. como segundo parámetro la página que procesará el dato enviado al servidor (en nuestro caso enviamos el valor entero comprendido entre 1 y 10. var aleatorio=Math. Imaginemos que votamos y .send(null). function cargarVoto(voto) { conexion1=crearXMLHttpRequest(). Otra cosa que vamos a incorporar es el envío de un valor aleatorio.firstChild. conexion1. } En la función presionBoton desactivamos la acción por defecto de un elemento "a" llamando a la función e.

open('POST'. } else { resultados. como hemos visto hasta ahora. $ar=fopen("votos.getElementById("resultados").$_REQUEST['voto'].readyState == 4) { resultados.txt". Podemos enviar los datos por el método GET.php?voto=10 del cache y no actualizar el archivo de texto con el voto seleccionado. fputs($ar.. fclose($ar). charset=ISO-8859-1'). La solución mas sencilla es enviar un parámetro con un valor aleatorio.Pasando datos al servidor por el método POST. Recordemos que el tercer parámetro de la función open indica que el proceso se efectúe en forma asincrónica (esto si le pasamos el valor true) La función procesarEventos obtiene una referencia al div llamado detalles y mustra inicialmente el texto: 'Cargando. true). luego cuando el servidor informa que los datos se registraron pasa a mostrar el texto: 'Gracias'. Hay varios puntos a tener en cuenta para cuando codificamos los datos para el envío por el método POST: 1.'. lo cual el navegador interpretará que se trata de otra página.'. pero también podemos enviar los datos por el método POST.'pagina1. El método POST se utiliza cuando hay que enviar mucha información al servidor."-\n")..."a") or die("No se pudo abrir el archivo")..asignamos el valor 10. conexion1.innerHTML = 'Gracias. luego si volvemos a seleccionar el 10 puede recuperar la pagina1.php) tiene por objetivo registrar en un archivo de texto el valor seleccionado por el visitante: <?php header('Content-Type: text/html.'. function procesarEventos() { var resultados = document. .php'. } } Por último la página que se ejecuta en el servidor (pagina1. Cuando llamamos al método open del objeto XMLHttpRequest como primer parámetro indicamos el string 'POST' 2. ?> 7 .innerHTML = 'Procesando. if(conexion1.

conexion1. El archivo funciones.txt">Ver resultados</a> </form> </body> </html> Este archivo HTML no tiene nada de especial. 5. 4. otro de tipo textarea y finalmente un botón para el envío de los datos al servidor. El formulario solicitará que ingrese el nombre y comentarios del sitio. esto con el objetivo de poder controlar si los datos realmente se cargaron en el servidor. Podemos concatenar datos extraidos de un formulario y enviarlos a través del método send. Llamamos al método setRequestHeader indicando que los datos a enviarse están codificados como un formulario. conexion1."application/x-wwwform-urlencoded").send("nombre=juan&clave=z80"). Haremos una serie de páginas que nos permitan enviar los datos cargados en un formulario al servidor en forma asincrónica y por lo tanto no tendremos que refrescar la página luego de enviado los datos. Confeccionaremos un problema completo para probar la funcionalidad del envío de datos por el método POST. básicamente es un formulario con un control de tipo input. Llamamos al método send del objeto XMLHttpRequest pasando los datos: 6.setRequestHeader("Content-Type".php" method="post" id="formulario"> Nombre:<input type="text" name="nombre" id="nombre" size="20"><br> Comentarios:<br> <textarea name="comentarios" id="comentarios" rows="10" cols="50"></textarea><br> <input type="submit" value="Enviar" id="enviar"> <div id="resultados"></div> <a href="comentarios.js es: .html): <html> <head> <title>Problema</title> <script src="funciones. En un problema más grande seguramente los datos los almacenaremos en una base de datos.3.js" language="JavaScript"></script> </head> <body> <form action="pagina1. Disponemos un hipervínculo al archivo de texto que almacenará los datos cargados. Además contiene un div vacío para mostrar mensajes sobre el resultado del envío de los datos al servidor. El archivo HTML es el siguiente (pagina1.

addEvent(window."application/x-www-form-urlencoded").'.onreadystatechange = procesarEventos.setRequestHeader("Content-Type".php'. return cad.'submit'.false).returnValue=false.getElementById('nombre'). } function procesarEventos() { var resultados = document.event. else if (e) e.'.false).getElementById('comentarios').preventDefault(). } function enviarDatos(e) { if (window.event) window.value..innerHTML = 'Gracias. function enviarFormulario() { conexion1=crearXMLHttpRequest(). conexion1. if(conexion1. conexion1.'load'. } var conexion1. cad='nombre='+encodeURIComponent(nom)+'&comentarios='+encodeURIComponent (com).enviarDatos.readyState == 4) { resultados. var nom=document.send(retornarDatos()). conexion1.getElementById('formulario'). enviarFormulario(). conexion1.value. } function retornarDatos() { var cad=''. true).getElementById("resultados"). function inicializarEventos() { var ref=document.innerHTML = 'Procesando. var com=document.. } else { resultados.'pagina1. addEvent(ref.open('POST'.inicializarEventos. } } .

return xmlHttp.XMLHTTP").attachEvent) { elemento. conexion1. else if (window.attachEvent('on'+nomevento.onreadystatechange = procesarEventos.getElementById('formulario'). Es decir la función enviarDatos se ejecutará cuando el operador presione el botón de tipo submit. } Lo primero que hacemos en la función inicializarEventos es: var ref=document.php'.enviarDatos.funcion.funcion.nomevento. return true.open('POST'. } .false).send(retornarDatos()).addEventListener(nomevento. conexion1. return true. true).setRequestHeader("Content-Type".captura) { if (elemento. Obtener la referencia del formulario e inicializar el evento submit para poder capturar el momento en que los datos se enviarán al servidor. addEvent(ref.//*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. } function crearXMLHttpRequest() { var xmlHttp=null.captura).funcion). } else return false. La función enviarFormulario: var conexion1. } else if (elemento. if (window.'pagina1.'submit'."application/x-www-formurlencoded"). conexion1.addEventListener) { elemento.XMLHttpRequest) xmlHttp = new XMLHttpRequest(). function enviarFormulario() { conexion1=crearXMLHttpRequest() conexion1.

value."\n\n").txt".value.Inicializa el objeto XMLHttpRequest indicando en el método open que los datos se enviarán mediante el comando POST.php <?php header('Content-Type: text/html."Comentarios:". charset=ISO-8859-1'). } Obtenemos el valor contenido en cada control (input y textarea) y luego concatenamos nombre del dato y valor separándolos por el caracter ámpersand.getElementById("resultados"). if(conexion1.$_REQUEST['nombre'].. fputs($ar. fclose($ar). Estos datos los recuperamos del formulario llamando a la función retornarDatos() que a continuación la explicaremos. var nom=document. Cuando retorna un 4 significa que el envío de datos se efectuó en forma correcta. return cad. function retornarDatos() { var cad=''. ."a") or die("No se pudo abrir el archivo").'. } else { resultados. Luego llamamos al método setRequestHeader indicando el tipo de contenido a enviar al servidor.innerHTML = 'Gracias.getElementById('nombre')."\n"). fputs($ar. $ar=fopen("comentarios.readyState == 4) { resultados. cad='nombre='+encodeURIComponent(nom)+'&comentarios='+encodeURIComponent( com).. var com=document. Otra cosa importante es llamar a la función JavaScript encodeURIComponent para codificar los datos ingresados por el visitante y se puedan enviar correctamente al servidor.innerHTML = 'Procesando. La función procesarEventos: function procesarEventos() { var resultados = document.'. Finalmente llamamos al método send con los datos. mostramos en ese momento el mensaje 'Gracias'. } } Dijimos ya que esta función se ejecuta cada vez que cambia el estado del objeto XMLHttpRequest."Nombre:".getElementById('comentarios'). El último archivo: pagina1.$_REQUEST['comentarios'].

'. if(conexion1. El archivo pagina1.js" language="JavaScript"></script> <link rel="StyleSheet" href="estilos. } else { detalles.innerHTML = conexion1. El objetivo es rescatar todos los comentarios para la fecha seleccionada por el visitante y su posterior visualización sin tener que recargar nuevamente la página.responseText. Lo más común es que tengamos un código similar al siguiente: function procesarEventos() { var detalles = document.innerHTML = 'Cargando. 8 . } } Confeccionaremos un ejemplo para identifiar donde utilizar la propiedad responseText.. El problema consiste en mostrar una lista de hipervínculos que representan los comentarios de distintas fecha.css" type="text/css"> </head> <body> <h2>Seleccione la fecha:</h2> <p> <div id="fecha"> . Esta propiedad almacena el valor devuelto por el servidor. esto ocurre cuando la propiedad readyState del objeto XMLHttpRequest almacena el valor 4.Recuperando datos mediante la propiedad responseText del objeto XMLHttpRequest Ahora nos concentraremos en la propiedad responseText del objeto XMLHttpRequest.readyState == 4) { detalles..?> Simplemente rescatamos los datos enviados desde el navegador y procedemos a grabarlos en el archivo de texto.getElementById("comentarios").html es: <html> <head> <title>Problema</title> <script src="funciones. Normalmente accederemos a la propiedad responseText cuando el objeto XMLHttpRequest nos informa que toda la información fue remitida por el servidor.

font-family:verdana. verComentarios(url). function inicializarEventos() { var ref.f++) { addEvent(vec[f].length.false).getElementsByTagName('a'). padding:5px.php?fecha=10/03/2007">ver comentarios del 10/03/2007</a><br> <a href="pagina1. var url=window.js es: addEvent(window.getElementById('fecha'). border: 1px dotted #ffaa00.presionEnlace.'click'.event) { window. ref=document.returnValue=false. } else . border-width:0.getAttribute('href').php?fecha=12/03/2007">ver comentarios del 12/03/2007</a><br> </div> <div class="recuadro" id="comentarios">Comentarios:</div> </body> Cada hipervínculo dispone como parámetro la fecha de la cual queremos recuperar los comentarios. } } function presionEnlace(e) { if (window.recuadro { background-color:#ffffcc.event.css es: . } Luego el archivo funciones. for(f=0.srcElement. Disponemos un div donde visualizaremos los comentarios de la fecha seleccionada. La hoja de estilo estilos. var vec=ref.event.f<vec.'load'.php?fecha=11/03/2007">ver comentarios del 11/03/2007</a><br> <a href="pagina1.inicializarEventos. text-align:left.<a href="pagina1.false).

} function procesarEventos() { var detalles = document.'.attachEvent) { elemento.innerHTML = conexion1.funcion.captura) { if (elemento. true). if(conexion1. } else return false.preventDefault().if (e) { e. url.open("GET".send(null). var url=e.. } .funcion).innerHTML = 'Cargando. } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento. return true.addEventListener(nomevento.funcion.getAttribute('href'). } } var conexion1.onreadystatechange = procesarEventos. conexion1.attachEvent('on'+nomevento.. function verComentarios(url) { if(url=='') { return. } conexion1=crearXMLHttpRequest().addEventListener) { elemento.getElementById("comentarios").responseText.target.captura). conexion1. } else { detalles. return true.readyState == 4) { detalles. } else if (elemento.nomevento. verComentarios(url). conexion1.

function crearXMLHttpRequest() { var xmlHttp=null.false).XMLHttpRequest) xmlHttp = new XMLHttpRequest(). luego mediante un for inicializa el evento click para cada hipervínculo.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. else if (window. verComentarios(url).event) { window. } Obtiene la referencia a todas las a (anchor) contenidas en el div 'fecha'.getElementsByTagName('a').returnValue=false. } else if (e) { e. for(f=0.event. } La función inicializarEventos: var ref.srcElement.XMLHTTP").preventDefault().getElementById('fecha'). return xmlHttp. La función presionEnlace se dispara cuando se presiona alguno de los hipervínculos: function presionEnlace(e) { if (window.presionEnlace.'click'. var url=e. ref=document.f++) { addEvent(vec[f]. verComentarios(url). var vec=ref. } } Primero desactivamos el evento por defecto y llamamos a la función verComentarios pasando como referencia el parámetro del hipervínculo.getAttribute('href').event. La función verComentarios : var conexion1.f<vec.length. if (window. function verComentarios(url) { if(url=='') . var url=window.getAttribute('href').target.

} } En esta función mientras la propiedad readyState del objeto XMLHttpRequest almacene un valor distinto a 4 significa que el proceso no a finalizado. } conexion1=crearXMLHttpRequest() conexion1.onreadystatechange = procesarEventos.innerHTML = conexion1.responseText. if(conexion1. Como parámetro a este método indicamos el valor null ya que los datos viajan en la misma cabecera de petición de página (ej. conexion1. El tercer paso es llamar al método send. } else { detalles. Primero inicializamos la propiedad onreadystatechange con el nombre de la función que procesará los eventos del objeto XMLHttpRequest.send(null).open("GET". true).readyState == 4) { detalles.php): <?php if ($_REQUEST['fecha']=='10/03/2007') { echo "Estos comentarios corresponden a la fecha 10/03/2007<br>". .'.getElementById("comentarios").innerHTML = conexion1. conexion1.responseText. Como segundo paso llamamos al método open indicando que enviaremos la fecha mediante el método GET. Para simplificar el problema en el servidor evitamos rescatarlos de una base de datos (como ocurre en la realidad). luego el contenido de esta página es (pagina1... el siguiente parámetro el nombre de la página a llamar junto con la fecha a enviar y por último pasamos el valor true indicando que emplearemos comunicación asincrónica. 'pagina1.{ return. url. Cuando identificamos que tiene el valor 4 procedemos a modificar el div con el valor devuelto por el servidor: detalles. } Llama a la función crearXMLHttpRequest que retorna un objeto de tipo XMLHttpRequest y procede a almacenarlo en la variable conexion1 (que al ser una variable global podrá utilizarse y accederse desde otra función) Las siguientes tres líneas son similares a problemas que hemos realizado anteriormente.php?fecha=22/11/2007) La función procesarEventos es donde accedemos a la propiedad responseText: function procesarEventos() { var detalles = document.innerHTML = 'Cargando.

<br>". echo "zzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzz zzzzzzzzzzzzzz zzzzzz. echo "zzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzz zzzzzzzzzzzzzz zzzzzz. echo "yyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy. echo "xxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx.<br>". } if ($_REQUEST['fecha']=='11/03/2007') { echo "Estos comentarios corresponden a la fecha 11/03/2007<br>".<br>". echo "zzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzz zzzzzzzzzzzzzz zzzzzz. echo "zzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzz zzzzzzzzzzzzzz zzzzzz. echo "zzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzz zzzzzzzzzzzzzz zzzzzz.<br>". echo "yyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy.<br>".<br>". echo "xxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx.<br>".<br>". echo "yyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy.<br>". echo "xxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx.<br>".<br>".<br>".<br>".<br>".<br>". echo "zzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzz zzzzzzzzzzzzzz zzzzzz. } if ($_REQUEST['fecha']=='12/03/2007') { echo "Estos comentarios corresponden a la fecha 12/03/2007<br>".<br>".<br>".<br>".<br>".<br>".<br>". echo "xxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx. } .<br>".<br>". echo "zzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzz zzzzzzzzzzzzzz zzzzzz. echo "zzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzz zzzzzzzzzzzzzz zzzzzz. echo "xxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx. echo "zzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzz zzzzzzzzzzzzzz zzzzzz.<br>".echo "xxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx.<br>". echo "yyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy. echo "yyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy. echo "zzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzz zzzzzzzzzzzzzz zzzzzz.<br>". echo "xxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx. echo "xxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx. echo "zzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzz zzzzzzzzzzzzzz zzzzzz.<br>".<br>".<br>". echo "xxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx. echo "xxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx.<br>". echo "zzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzz zzzzzzzzzzzzzz zzzzzz. echo "yyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy.<br>".<br>". echo "yyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy. echo "yyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy yyyyyyyyyyyyyyyyyy. echo "xxxxxxxxxxxxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxx. echo "zzzzzzzzzzzzzzzzz zzzzzzzzzzzzzzz zzzzzzzzzzzzzz zzzzzz.

?>

9 - Recuperando datos mediante la propiedad responseXML del objeto XMLHttpRequest

La propiedad responseXML a diferencia de la propiedad responseText recupera los datos como XML y debemos recorrerlo mediante las funciones del DOM. Es necesario que el programa que se ejecute en el servidor estructure los datos en formato XML. Para probar el funcionamiento de esta propiedad del objeto XMLHttpRequest implementaremos una página que muestre en un control select los nombres de una serie de paises. Cuando se seleccione uno y se presione un botón recuperaremos de dicho pais el nombre de la capital, su superficie, cantidad de habitantes y su idioma. El servidor generará un archivo con formato XML y lo retornará al cliente. El primer archivo (pagina1.html): <html> <head> <title>Problema</title> <script src="funciones.js" language="JavaScript"></script> </head> <body> <h1>Datos de paises.</h1> <p>Seleccione el pais <select id="pais"> <option value="0" selected>seleccione</option> <option value="Argentina">Argentina</option> <option value="Brasil">Brasil</option> <option value="Chile">Chile</option> </select><br> <input type="button" id="boton1" value="Recuperar"> </p> <div id="resultados"></div> </body> </html> Este archivo HTML no tiene nada nuevo. El archivo que contiene las funciones JavaScript (funciones.js): addEvent(window,'load',inicializarEventos,false); function inicializarEventos() { var ob=document.getElementById('boton1');

addEvent(ob,'click',presionBoton,false); } function presionBoton(e) { var ob1=document.getElementById('pais'); recuperarDatos(ob1.value); } var conexion1; function recuperarDatos(pais) { conexion1=crearXMLHttpRequest(); conexion1.onreadystatechange = procesarEventos; conexion1.open('GET','pagina1.php?pa='+pais, true); conexion1.send(null); } function procesarEventos() { var resultados = document.getElementById("resultados"); if(conexion1.readyState == 4) { var xml = conexion1.responseXML; var capital=xml.getElementsByTagName('capital'); var superficie=xml.getElementsByTagName('superficie'); var idioma=xml.getElementsByTagName('idioma'); var poblacion=xml.getElementsByTagName('poblacion'); resultados.innerHTML='Capital='+capital[0].firstChild.nodeValue + '<br>' + 'Superficie='+superficie[0].firstChild.nodeValue + '<br>' + 'Idioma='+idioma[0].firstChild.nodeValue + '<br>' + 'Poblacion='+poblacion[0].firstChild.nodeValue ; } else { resultados.innerHTML = 'Cargando...'; } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento,nomevento,funcion,captura) { if (elemento.attachEvent) { elemento.attachEvent('on'+nomevento,funcion); return true; } else if (elemento.addEventListener) { elemento.addEventListener(nomevento,funcion,captura);

return true; } else return false; } function crearXMLHttpRequest() { var xmlHttp=null; if (window.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); else if (window.XMLHttpRequest) xmlHttp = new XMLHttpRequest(); return xmlHttp; } En la primer función que se ejecuta enlazamos la función a ejecutar al presionar el botón: var ob=document.getElementById('boton1'); addEvent(ob,'click',presionBoton,false); Cuando se presiona el botón se ejecuta la función presionBoton: function presionBoton(e) { var ob1=document.getElementById('pais'); recuperarDatos(ob1.value); } Recuperamos el pais seleccionado en el control select y llamamos a la función recuperarDatos pasando como parámetro dicho pais. La función recuperarDatos crea un objeto de la clase XMLHttpRequest y abre una conexión con el servidor mediante el método GET pasando como parámetro el nombre del pais seleccionado: var conexion1; function recuperarDatos(pais) { conexion1=crearXMLHttpRequest() conexion1.onreadystatechange = procesarEventos; conexion1.open('GET','pagina1.php?pa='+pais, true); conexion1.send(null); } Como sabemos la propiedad onreadystatechange se inicializa con el nombre de la función que procesará los cambios de estado del objeto XMLHttpRequest. En este caso el algoritmo de la función es: function procesarEventos() { var resultados = document.getElementById("resultados"); if(conexion1.readyState == 4)

. Esta línea genera un vector con las referencias a todos los elementos llamados 'capital' (En nuestro caso hay uno solo) Como se trata de un vector luego debemos accederlo por medio de un subíndice (indicamos el valor cero ya que contiene solo un elemento): capital[0]. var idioma=xml..innerHTML='Capital='+capital[0].innerHTML = 'Cargando. $capital="Buenos Aires".nodeValue + '<br>' + 'Poblacion='+poblacion[0]. Por último para acceder a la información de dicho nodo de texto lo hacemos mediante la propiedad nodeValue (Tener en cuenta que todos estos conceptos se ven detenidamente en el tutorial de DHTML) El último archivo que integra este problema es el que se ejecuta en el servidor (pagina1.getElementsByTagName('poblacion').php): <?php if ($_REQUEST['pa']=='Argentina') { $superficie=2700000.getElementsByTagName('capital'). Primero almacenamos la información en la variable xml: var xml = conexion1.firstChild. } } Cuando los datos han llegado completamente..nodeValue + '<br>' + 'Superficie='+superficie[0].firstChild. Ahora podemos recorrer el archivo XML mediante las funciones que provee el DOM.firstChild.nodeValue .nodeValue + '<br>' + 'Idioma='+idioma[0]. var poblacion=xml. resultados. var capital=xml.nodeValue Como sabemos el texto contenido entre las marcas se trata de otro nodo y lo podemos acceder mediante el método firstChild.responseXML.getElementsByTagName('idioma').firstChild.getElementsByTagName('capital').firstChild. var superficie=xml.getElementsByTagName('superficie'). } else { resultados. var capital=xml. es decir la propiedad readyState del objeto XMLHttpRequest almacena el valor 4 procedemos a cargar los datos dentro del div 'resultados'.'.{ var xml = conexion1.responseXML.

$xml. Finalmente procedemos a imprimir la variable $xml luego de enviar la cabecera al navegador. 10 .="<poblacion>$poblacion</poblacion>\n".Propiedades onreadystatechange y readystate.="<idioma>$idioma</idioma>\n". El objetivo de cada una es:   onreadystatechange Almacena el nombre de la función que se ejecutará cuando el objeto XMLHttpRequest cambie de estado. $xml.="<superficie>$superficie</superficie>\n".="<capital>$capital</capital>\n".="</pais>\n". pudiendo ser: . $poblacion=15000000. Mediante la función header informamos al navegador que se trata de un archivo XML. readyState Almacena el estado del requerimiento hecho al servidor. $idioma="Castellano". $poblacion=163000000. } if ($_REQUEST['pa']=='Brasil') { $superficie=8500000. ?> Nuevamente para simplificar el problema no hemos almacenado los datos de los paises en una base de datos. Dos propiedades fundamentales del objeto XMLHttpRequest son onreadystatechange y readyState.$idioma="Castellano".="<pais>\n". $xml. echo $xml. $xml. Por último creamos un string organizando la información con formato XML.0\"?>\n". $xml. Mediante una serie de if verificamos de que pais se trata e inicializamos cuatro variables. } $xml="<?xml version=\"1. $capital="Brasilia". } if ($_REQUEST['pa']=='Chile') { $superficie=750000. header('Content-Type: text/xml'). $xml. $capital="Santiago". $idioma="Portugues". $poblacion=38000000.

html> <html> <head> <title>Problema</title> <script src="funciones.php" method="post" id="formulario"> Ingrese nro:<input type="text" name="nro" id="nro" .getElementById("detalles"). url.. } } Para ver el paso de estados del objeto XMLHttpRequest implementaremos una aplicación que calcule el cuadrado de un número que ingresamos por teclado.responseText. pagina1.innerHTML = 'Cargando.o o o o o 0 No inicializado (el método open no a sido llamado) 1 Cargando (se llamó al método open) 2 Cargado (se llamó al método send y ya tenemos la cabecera de la petición HTTP y el status) 3 Interactivo (la propiedad responseText tiene datos parciales) 4 Completado (la propiedad responseText tiene todos los datos pedidos al servidor) Normalmente cuando creamos un objeto de la clase XMLHttpRequest inicializamos la propiedad onreadystatechange con el nombre de la función que procesará los datos enviados por el servidor: function cargarHoroscopo(url) { if(url=='') { return. Y además mostraremos mediante un alert el estado actual de la propiedad readyState.innerHTML = conexion1.readyState == 4) { detalles.send(null).. } conexion1=crearXMLHttpRequest(). conexion1. true).onreadystatechange = procesarEventos.js" language="JavaScript"></script> </head> <body> <form action="pagina1. conexion1.open("GET". } Por otro lado dentro de la función que previamente fue asignada a la propiedad onreadystatechange verificamos el estado de la propiedad readyState: function procesarEventos() { var detalles = document. if(conexion1. conexion1. } else { detalles.'.

} var conexion1. enviarFormulario().enviarDatos.. alert('Valor de la propiedad readyState:'+conexion1.send(null).responseText. function inicializarEventos() { var ref=document.inicializarEventos.readyState==3) { resultados. } else if (conexion1.readyState). addEvent(ref.innerHTML = 'Procesando. if(conexion1.readyState == 4) { resultados.false).getElementById("resultados").readyState==2 || conexion1. conexion1.getElementById('nro'). conexion1.onreadystatechange = procesarEventos. else if (e) e.size="10"><br> <input type="submit" value="Calcular el cuadrado" id="enviar"> <div id="resultados"></div> </form> </body> </html> funciones.preventDefault().innerHTML = conexion1.js addEvent(window.'pagina1. } function enviarDatos(e) { if (window.'load'. } .readyState).false).returnValue=false.getElementById('formulario').'submit'. function enviarFormulario() { conexion1=crearXMLHttpRequest() conexion1. var resultados = document.value.readyState==1 || conexion1. var num=document. } function procesarEventos() { alert('Valor de la propiedad readyState:'+conexion1. true).'.event) window.php?numero='+num.open('GET'.event..

ActiveXObject) xmlHttp = new ActiveXObject("Microsoft.attachEvent('on'+nomevento.readyState). if (window. . } Como podemos observar si accedemos a la propiedad readyState antes de llamar a los métodos open y send la misma almacena el valor cero: conexion1=crearXMLHttpRequest() conexion1. //Muestra cero Cuando llamamos al método open se ejecuta por primera vez la función que inicializamos en la propiedad onreadystatechange. } else if (elemento.funcion).XMLHttpRequest) xmlHttp = new XMLHttpRequest().captura) { if (elemento. true). } function crearXMLHttpRequest() { var xmlHttp=null. alert('Valor de la propiedad readyState:'+conexion1. } else return false.XMLHTTP").funcion.'pagina1. return xmlHttp.captura).attachEvent) { elemento. var num=document.value. return true.getElementById('nro'). return true.onreadystatechange = procesarEventos. else if (window.funcion.addEventListener) { elemento.open('GET'. al mostrar la propiedad readyState veremos que almacena un uno: conexion1.php?numero='+num.addEventListener(nomevento.nomevento.} //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.

?> 11 .readyState).readyState == 4) { resultados.innerHTML = 'Procesando.responseText.3 y 4.. } } mostrará los valores 2. Estas dos propiedades todavía no las habíamos utilizado. Entre otros valores que puede retornar el servidor: 200 es el valor para una conexión exitosa.readyState==1 || conexion1.Propiedades status y statusText.'. Esta propiedad de solo lectura esta disponible cuando readyState toma los valores 3 o 4.innerHTML = conexion1. 404 página inexistente.php <?php $cuadrado=$_REQUEST['numero']*$_REQUEST['numero']. Veremos que las mismas nos permiten hacer un código más correcto. var resultados = document.  .getElementById("resultados").Cuando llamamos al método send se ejecuta por segunda vez la función que inicializamos en la propiedad onreadystatechange.readyState==3) { resultados. Recordemos: o o o o o 0 No inicializado (el método open no a sido llamado) 1 Cargando (se llamó al método open) 2 Cargado (se llamó al método send y ya tenemos la cabecera de la petición HTTP y el status) 3 Interactivo (la propiedad responseText tiene datos parciales) 4 Completado (la propiedad responseText tiene todos los datos pedidos al servidor) pagina1. statusText Almacena el texto de la petición HTTP enviado por el servidor. Luego la función: function procesarEventos() { alert('Valor de la propiedad readyState:'+conexion1. al mostrar la propiedad readyState veremos que continua con el valor uno..  status Esta propiedad almacena el código del estado de la petición HTTP. } else if (conexion1.readyState==2 || conexion1. if(conexion1. echo $cuadrado.

'load'.onreadystatechange = procesarEventos.js addEvent(window.getElementById('formulario').returnValue=false.event) window. addEvent(ref. pagina1.enviarDatos.preventDefault(). .Con estas nuevas propiedades veremos que lo más correcto cuando readyState contiene el valor 4 debemos además verificar si la propiedad status almacena el valor 200 (es decir el servidor procesó correctamente la petición) Para probar estas propiedades confeccionaremos el problema del concepto anterior (retornar del servidor el cuadrado de un número que ingresamos por teclado). function enviarFormulario() { conexion1=crearXMLHttpRequest().'submit'. } function enviarDatos(e) { if (window. else if (e) e.false). introduciremos un error (el método open llamará a una página php inexistente) y veremos cual es el mensaje en pantalla. enviarFormulario(). conexion1.inicializarEventos.js" language="JavaScript"></script> </head> <body> <form action="pagina1. function inicializarEventos() { var ref=document. luego agregaremos la verificación de la propiedad status.html <html> <head> <title>Problema</title> <script src="funciones. } var conexion1.php" method="post" id="formulario"> Ingrese nro:<input type="text" name="nro" id="nro" size="10"><br> <input type="submit" value="Calcular el cuadrado" id="enviar"> <div id="resultados"></div> </form> </body> </html> funciones.event.false).

.readyState==2 || conexion1.captura) { if (elemento.XMLHTTP"). } else if (elemento. } else if (conexion1.var num=document. return true.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft.open('GET'. return true.getElementById('nro'). } function procesarEventos() { var resultados = document. } else return false.funcion). } .getElementById("resultados").addEventListener(nomevento. return xmlHttp.funcion.responseText.XMLHttpRequest) xmlHttp = new XMLHttpRequest().attachEvent('on'+nomevento..send(null). conexion1. conexion1. true).nomevento.php?numero='+num.value.readyState == 4) { resultados.attachEvent) { elemento. } function crearXMLHttpRequest() { var xmlHttp=null.innerHTML = conexion1.innerHTML = 'Procesando.'. else if (window. if (window. if(conexion1.addEventListener) { elemento.captura).funcion.'paginax.readyState==3) { resultados. } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.readyState==1 || conexion1.

Luego modifique el archivo funciones. } } else if (conexion1.'paginax. echo $cuadrado.. .' y mostramos en un alert el texto del error devuelto por el servidor .innerHTML=''.readyState == 4) { if (conexion1.En este archivo podemos ver el error que hemos introducido: conexion1..status==200) { resultados.getElementById("resultados").readyState==3) { resultados.readyState==2 || conexion1.open('GET'.responseText.php donde debíamos disponer pagina1..innerHTML = conexion1. } else { resultados.. if(conexion1. true).js verificando el estado de la propipedad status: function procesarEventos() { var resultados = document.statusText).innerHTML = 'Procesando.readyState==1 || conexion1. } } Es decir que no solo debemos verificar que la propiedad readyState tenga almacenado un 4. 12 . sino que la propiedad status retorne un 200. pagina1. ?> Cuando ejecute estas páginas deberá ver un mensaje parecido a: "Page Not Found".Método abort del objeto XMLHttpRequest El objeto XMLHttpRequest tiene un método llamado abort que tiene por objetivo detener la conexión establecida.php?numero='+num. alert(conexion1.php.'.php <?php $cuadrado=$_REQUEST['numero']*$_REQUEST['numero']. En este caso por el else solamente borramos el div donde aparece el texto 'Procesando. Hemos pasado como nombre de página: paginax.

Nuestra página HTML es (pagina1.php?cod=9">Sagitario</a></p> <p><a id="enlace10" href="pagina1.php?cod=1">Aries</a></p> <p><a id="enlace2" href="pagina1. además mediante este método (abort) cancelamos la petición. margin:5px.php?cod=12">Piscis</a></p> </div> <div id="detalles">Seleccione su signo. Confeccionaremos el primer problema planteado en este tutorial: Confeccionar un problema que muestre una lista de hipervínculos con los distintos signos del horóscopo y luego al ser presionado no recargue la página completa sino que se envíe una petición al servidor y el mismo retorne la información de dicho signo.css: #menu { font-family: Arial.js" language="JavaScript"></script> <link rel="StyleSheet" href="estilos.php?cod=2">Tauro</a></p> <p><a id="enlace3" href="pagina1.php?cod=5">Leo</a></p> <p><a id="enlace6" href="pagina1.Hay situaciones donde el servidor se encuentra saturado y no puede devolver una petición. luego se actualice solo el contenido de un div del archivo HTML.css" type="text/css"> </head> <body> <h1>Signos del horóscopo.php?cod=6">Virgo</a></p> <p><a id="enlace7" href="pagina1.php?cod=7">Libra</a></p> <p><a id="enlace8" href="pagina1. Para simular el efecto de saturación del servidor utilizaremos en el programa PHP la llamada a la función sleep que tiene por objetivo detener una determinada cantidad de segundos la ejecución del programa PHP.</div> </body> </html> El archivo estilos. Le agregaremos que si en tres segundos el estado de petición no a finalizado mostraremos un mensaje al usuario indicando que el servidor se encuentra saturado.php?cod=3">Geminis</a></p> <p><a id="enlace4" href="pagina1.php?cod=11">Acuario</a></p> <p><a id="enlace12" href="pagina1.</h1> <div id="menu"> <p><a id="enlace1" href="pagina1. .php?cod=4">Cancer</a></p> <p><a id="enlace5" href="pagina1.html): <html> <head> <title>Problema</title> <script src="funciones.php?cod=8">Escorpio</a></p> <p><a id="enlace9" href="pagina1. En estas situaciones es bueno mostrar un mensaje al usuario del sitio que indique el prlblema.php?cod=10">Capricornio</a></p> <p><a id="enlace11" href="pagina1.

padding:5px. margin:5px. for(f=1. } #menu a { display: block.} #menu p { margin:0px. padding: 3px. text-align:left. } #menu a:hover { background-color: #369.f<=12.'load'.inicializarEventos. background-color: #f7f8e8. text-decoration: none. } #menu a:link. function inicializarEventos() { var ob. border-width:0. addEvent(ob.getElementById('enlace'+f).'click'.js addEvent(window.f++) { ob=document.false). border: 1px dotted #fa0. } } function presionEnlace(e) { . #menu a:visited { color: #f00. text-align:center. font-family:verdana. } #detalles { background-color:#ffc. border-bottom: 1px solid #eee. padding:0px.presionEnlace. width: 160px. } El archivo funciones. color: #fff.false).

getAttribute('href').srcElement. url. detalles.returnValue=false. conexion1. true). var url=window.innerHTML = conexion1.getAttribute('href').3000)..'. } else if (e) { e.event.send(null).event.readyState == 4) { clearTimeout(tiempo). } else if(conexion1. el servidor esta sobrecargado. tiempo=setTimeout("finDeEspera()". if(conexion1. } function procesarEventos() { var detalles = document. } conexion1=crearXMLHttpRequest().innerHTML = 'Intente nuevamente más tarde. } } var conexion1. } //*************************************** //Funciones comunes a todos los problemas .readyState == 1) { detalles.getElementById("detalles").target.preventDefault(). var tiempo.event) { window..if (window.open("GET". detalles. conexion1. var url=e.innerHTML = 'Cargando. } } function finDeEspera() { conexion1.onreadystatechange = procesarEventos.responseText.'.abort(). conexion1. cargarHoroscopo(url). cargarHoroscopo(url). function cargarHoroscopo(url) { if(url=='') { return.

La variable tiempo guarda una referencia al temporizador. return xmlHttp. function finDeEspera() { conexion1. return true. el servidor esta sobrecargado.XMLHTTP").abort().3000).captura).XMLHttpRequest) xmlHttp = new XMLHttpRequest().funcion). con el objetivo de poderlo detener si la respuesta demora menos de 3 segundos. if (window.funcion. tiempo=setTimeout("finDeEspera()". } else return false.funcion. detalles.addEventListener) { elemento. else if (window.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. } En este archivo tenemos que cuando comenzamos la conexión con el servidor inicializamos un temporizador para que si pasan más de 3 segundos sin responder el servidor proceda a abortar esa conexión e informe al visitante.nomevento.innerHTML = 'Intente nuevamente más tarde.//*************************************** function addEvent(elemento. .'.attachEvent('on'+nomevento.responseText. return true. if(conexion1. detalles. } Aca podemos ver que si la petición finaliza procedemos a desabilitar el temporizador llamando a la función clearTimeout. } function crearXMLHttpRequest() { var xmlHttp=null.innerHTML = conexion1.captura) { if (elemento.attachEvent) { elemento. } else if (elemento.addEventListener(nomevento.readyState == 4) { clearTimeout(tiempo).

if ($_REQUEST['cod']==2) echo "<strong>Tauro:</strong> Hoy los cambios serán privados. Pensamientos. Mucha energía sexual y fuerza emocional.". Asuntos en lugares de retiro. Actividad en relación a estos temas. tal vez miedos. temas legales. Día esperanzado. Experiencias extrañas. Mostramos además un mensaje al usuario del sitio. Actividad laboral agradable.". solidaridad. el extranjero y la espiritualidad serán lo importante. Aca es donde procedemos a llamar al método abort del objeto XMLHttpRequest. if ($_REQUEST['cod']==7) echo "<strong>Libra:</strong> Hoy todo asunto tiene que ver con tu pareja. Ayuda. . de carácter. if ($_REQUEST['cod']==3) echo "<strong>Géminis:</strong> Los asuntos de hoy tienen que ver con las amistades.} La función finDeEspera se ejecutará si pasan 3 segundos sin finalizar el envio de datos del servidor. Ellos serán lo más importante del día.".". personales. if ($_REQUEST['cod']==4) echo "<strong>Cancer:</strong> Este día la profesión y las relaciones con superiores y con tu madre serán de importancia. Deseos difíciles de controlar. Recuerdos. Ganancias a través de especulaciones o del juego.". Por último nuestra archivo pagina1. también con socios. religión y filosofía también. if ($_REQUEST['cod']==5) echo "<strong>Leo:</strong> Este día los estudios. Actividades vocacionales artísticas. Vivencias kármicas de la época te vuelven responsable tomando decisiones. o de ayuda a los demás. Período en donde considerarás unirte a agrupaciones de beneficencia. actividades con ellos. juicios o herencias. reuniones. if ($_REQUEST['cod']==6) echo "<strong>Virgo:</strong> Para este día toma importancia tu vida sexual. con la gente o el público.php: <?php sleep(4).". Te sentirás impulsivo y tomarás iniciativas.". Tu cónyuge puede aportar buen status a tu vida o apoyo a tu profesión. if ($_REQUEST['cod']==1) echo "<strong>Aries:</strong> Hoy los cambios serán físicos. íntimos. ilusiones. Momentos positivos con compañeros de trabajo. Hay karma de prueba durante este período en tu parte psicológica. los viajes. generándose algunos replanteos.

if ($_REQUEST['cod']==10) echo "<strong>Capricornio:</strong> Los cambios del día tienen que ver con tu hogar. 13 . Asuntos relativos al carácter en la convivencia.. Hasta ahora mientras se actualiza la página mostramos un texto: 'Procesando. .. Presta atención a ambos. if ($_REQUEST['cod']==9) echo "<strong>Sagitario:</strong> Durante este día se vivirán cambios en relación a los noviazgos o a los hijos. con la convivencia y con el padre. hermanos y vecinos. mucha madurez y contacto con el más allá.Mostrar un gif animado mientras se envían y reciben los datos del servidor.if ($_REQUEST['cod']==8) echo "<strong>Escorpio:</strong> Hoy todo asunto tiene que ver con temas de trabajo y de salud. Período de encuentros con personas o situaciones que te impresionan. tiempo suficiente para que el programa JavaScript del navegador aborte la conexión e informe de la situación al usuario. ?> Hay que tener en cuenta que para poder simular el efecto de saturación del servidor hemos llamado a la función sleep(4) para que detenga la ejecución del programa durante 4 segundos. Pruebe luego de quitar la función sleep y compruebe el funcionamiento correcto del sitio.".". diversiones y salidas. Creatividad. actividad. El hablar y trasladarse será importante hoy. con la comunicación.". movimientos en los ingresos.'. Mentalidad e ideas activas.". buscarás el liderazgo. Experiencias diversas con compañeros. if ($_REQUEST['cod']==12) echo "<strong>Piscis:</strong> Durante este día se vivirán cambios en la economía. El karma de responsabilidad de estos momentos te acercará al mundo de lo desconocido.". negocios. valores. los viajes cortos o traslados frecuentes. Durante este período tendrás muchos recursos para ganar dinero. if ($_REQUEST['cod']==11) echo "<strong>Acuario:</strong> Hoy todo asunto tiene que ver con el entorno inmediato. Momentos de gran fuerza y decisión profesionales. es muy común utilizar un gif animado que represente tal operación.

inicializarEventos.html <html> <head> <title>Problema</title> <script src="funciones.preventDefault(). function inicializarEventos() { var ref=document.event) window.Haremos una serie de páginas que nos permitan enviar los datos cargados en un formulario al servidor en forma asincrónica y mostraremos un gif animado mientras dura el envío de datos.'submit'.false).js" language="JavaScript"></script> </head> <body> <form action="pagina1. addEvent(ref.js addEvent(window.returnValue=false.enviarDatos.txt">Ver resultados</a> </form> </body> </html> Hemos dispuesto un elemento span donde insertaremos el gif animado. El formulario solicitará que ingrese el nombre y sus comentarios.event.php" method="post" id="formulario"> Nombre:<input type="text" name="nombre" id="nombre" size="20"><br> Comentarios:<br> <textarea name="comentarios" id="comentarios" rows="10" cols="50"></textarea><br> <input type="submit" value="Enviar" id="enviar"> <span id="resultados"></span><br> <a href="comentarios. } function retornarDatos() { . else if (e) e. } function enviarDatos(e) { if (window. funciones. Utilizamos un span para que aparezca la imagen al lado del botón submit. pagina1.false).'load'.getElementById('formulario'). enviarFormulario().

statusText). } else { resultados.attachEvent) { elemento.funcion. } function procesarEventos() { var resultados = document. else alert(conexion1.'pagina1.getElementById("resultados").var cad=''.funcion.php'."application/x-www-form-urlencoded"). conexion1. return cad.addEventListener) { elemento.getElementById('nombre').send(retornarDatos()). } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.readyState == 4) { if (conexion1. var nom=document. return true. } var conexion1.onreadystatechange = procesarEventos.gif">'.'. } else if (elemento.setRequestHeader("Content-Type".innerHTML = 'Gracias.status==200) resultados. true).captura) { if (elemento./cargando.funcion).getElementById('comentarios').attachEvent('on'+nomevento.. cad='nombre='+encodeURIComponent(nom)+'&comentarios='+encodeURIComponent (com).value. conexion1.open('POST'. conexion1. function enviarFormulario() { conexion1=crearXMLHttpRequest().captura).addEventListener(nomevento.innerHTML = '<img src=". var com=document.nomevento. conexion1. return true.value. if(conexion1. } .

"\n"). fputs($ar. $ar=fopen("comentarios."Comentarios:". ?> En la página PHP grabamos en un archivo de texto los datos y mediante la función sleep detenemos la ejecución del programa en el servidor una determinada cantidad de segundos (esto para poder apreciar en el navegador el gif..else return false. Sin utilizar AJAX estamos obligados a recargar completamente la página lo que haría imposible ver el video y recorrer los comentarios en forma completa (considerando que solo parte de los comentarios están en la página) . Es decir insertamos una imagen dentro del elemento span. return xmlHttp.html <?php header('Content-Type: text/html.$_REQUEST['comentarios'].$_REQUEST['nombre']. fclose($ar)."\n\n"). else if (window.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. } Lo nuevo en este problema es: resultados. La imagen se encuentra en el directorio inmediatamente superior a donde se encuentra esta página (por eso disponemos ./cargando.innerHTML = '<img src=". fputs($ar.. } function crearXMLHttpRequest() { var xmlHttp=null. en la realidad no hay que llamar a sleep) 14 . Confeccionaremos una página que muestre un video e inmediatamente en la parte inferior mostraremos los comentarios del video paginados.txt"."Nombre:".XMLHTTP")."a") or die("No se pudo abrir el archivo"). if (window. sleep(1)./ previo al nombre del archivo) pagina1.Paginación con AJAX Un lugar donde puede ayudar el uso de AJAX es en la paginación de datos mientras otro recurso en la página se está ejecutando.gif">'. charset=ISO-8859-1').XMLHttpRequest) xmlHttp = new XMLHttpRequest().

php'). function inicializarEventos() { cargarPagina('pagina2. pagina1. cargarPagina(url). var url=window. Es dentro de este div donde iremos mostrando los comentarios en forma asincrónica.'load'. } else if (e) { e.Veamos y expliquemos cada uno de los archivos que intervienen.js" language="JavaScript"></script> </head> <body> <object width="425" height="350"><param name="movie" value="http://www. El archivo funciones.returnValue=false.event.getAttribute('href'). También es importante notar que hemos dispuesto un div vacío cuyo id se llama detalles. } function presionEnlace(e) { if (window.target.com/v/60og9gwKh1o" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"></embed></object> <br> <div id="detalles"> </div> </body> </html> Este archivo HTML no tiene nada de especial.event) { window.false). Podemos decir que hemos incrustado un video del sito youtube.youtube.getAttribute('href'). var url=e.event. } .preventDefault(). cargarPagina(url).com/v/60og9gwKh1o"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.js addEvent(window.srcElement.html <html> <head> <title>Problema</title> <script src="funciones.inicializarEventos.

attachEvent('on'+nomevento. var ob2=document.send(null).innerHTML = ' } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.addEventListener(nomevento. conexion1. } else if (elemento.attachEvent) { elemento. return true.getElementById('sig').presionEnlace. conexion1. conexion1.getElementById('ant'). '. function cargarPagina(url) { if(url=='') { return.funcion. url.'click'.readyState == 4) { detalles.onreadystatechange = procesarEventos. . var ob1=document. if (ob2!=null) addEvent(ob2.false). } function procesarEventos() { var detalles = document. } else { detalles.getElementById("detalles").nomevento.responseText.captura).open("GET". return true.presionEnlace.'click'. } conexion1=crearXMLHttpRequest().innerHTML = conexion1. if (ob1!=null) addEvent(ob1.funcion). true).captura) { if (elemento.funcion.false).} var conexion1. if(conexion1.addEventListener) { elemento.

} La función procesarEventos: function procesarEventos() { var detalles = document.readyState == 4) { detalles. La función cargarPagina es la que crea un objeto de la clase XMLHttpRequest: var conexion1.} else return false. true). } function crearXMLHttpRequest() { var xmlHttp=null. if (window.XMLHTTP"). url. if (ob1!=null) .getElementById("detalles"). function cargarPagina(url) { if(url=='') { return.send(null). return xmlHttp. } Dentro de esta función llamamos a la función cargarPagina con el nombre del archivo php que se ejecuta en el servidor y tiene por objetivo enviarnos los comentarios.XMLHttpRequest) xmlHttp = new XMLHttpRequest().innerHTML = conexion1. if(conexion1. } Como sabemos la primer función que se ejecuta al terminar de cargar la página es inicializarEventos: function inicializarEventos() { cargarPagina('pagina2.open("GET". conexion1. conexion1.php').onreadystatechange = procesarEventos.getElementById('sig'). else if (window.responseText.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. var ob1=document. conexion1. } conexion1=crearXMLHttpRequest().

"root"."<br>".innerHTML = conexion1.3".$reg['fecha']. else $inicio=0.false). $conexion=mysql_connect("localhost". } '.$reg['descripcion'].addEvent(ob1. var ob2=document.false).php: <?php header('Content-Type: text/html.getElementById('ant').'click'. echo "<br>".presionEnlace.getElementById('ant'). Es importante notar los if.false). if (ob2!=null) addEvent(ob2. echo "Nombre:".$reg['nombre'].presionEnlace. Esto debido a que cuando no hay más registros que mostrar no habrá un hipervínculo.'click'. mysql_select_db("bdajax". Imagine que la primer página no tiene que tener un hipervínculo "Anteriores"."<br>".'click'.presionEnlace. $impresos=0.false).$conexion) or die("Problemas en la seleccion de la base de datos").mysql_error()). . echo "Fecha:".getElementById('sig').innerHTML = ' } } Cuando la propiedad readyState tiene un cuatro procedemos a cargar el div "detalles" con el trozo de HTML que se generó en el servidor: detalles. var ob2=document. if (ob1!=null) addEvent(ob1."z80") or die("Problemas en la conexion").responseText. $conexion) or die("Problemas en el select:". Por último tenemos el archivo pagina2. } else { detalles. charset=ISO-8859-1'). if (ob2!=null) addEvent(ob2. $registros=mysql_query("select * from comentarios limit $inicio. while ($reg=mysql_fetch_array($registros)) { $impresos++. if (isset($_REQUEST['pos'])) $inicio=$_REQUEST['pos'].'click'. Otra cosa muy importante es inicializar el evento click para los hipervínculos siguiente y anterior que contiene todo listado con paginación: var ob1=document."<br>".presionEnlace. echo "Comentarios:".

echo "<a href=\"pagina2. else ."<br>".$reg['fecha']. else { $anterior=$inicio-3.$reg['nombre'].php?pos=$proximo\" id=\"sig\">Siguientes</a>". echo "<a href=\"pagina2. $inicio nos sirve para saber a partir de cual registro debemos rescatar. echo "<br>". while ($reg=mysql_fetch_array($registros)) { $impresos++.php sin especificar parámetros.mysql_close($conexion)."<br>". echo "Comentarios:". Mediante un while recorremos los registros rescatados y los imprimimos con el comando echo. else $inicio=0. en caso que sea distinto a cero creamos un hipervínculo y pasamos como parámetro el valor de $inicio menos 3: if ($inicio==0) echo "anteriores ". Es decir la variable $incio se inicializa con 0. como habíamos visto desde el inicializar eventos indicabamos cargar la página pagina2. } else echo "siguientes". } Si $inicio vale cero significa que no hay registros anteriores.mysql_error())."<br>". $conexion) or die("Problemas en el select:".php?pos=$anterior\" id=\"ant\">Anteriores </a>". Luego de conectarnos y seleccionar la base de datos procedemos a efectuar un select utilizando el limit para rescatar hasta tres registros (es decir página de tamaño 2): $registros=mysql_query("select * from comentarios limit $inicio.$reg['descripcion']. if (isset($_REQUEST['pos'])) $inicio=$_REQUEST['pos']. Además utilizamos un contador para saber cuantos registros se imprimieron: $impresos=0. } if ($impresos==3) { $proximo=$inicio+3. echo "Nombre:". if ($inicio==0) echo "anteriores ". echo "Fecha:". ?> Lo primero que hacemos es verificar si llega el parámetro pos.3".

En el primero almacenaremos una lista de carreras de estudio ("Analista de Sistemas".</option> <option value="1">Analista de sistemas</option> <option value="2">Telecomunicaciones</option> <option value="3">WebMaster</option> </select><span id="espera"></span><br> Materias de la carrera: <select id="materias" name="materias"> </select><br> </body> </html> Luego el archivo que contiene las funciones de JavaScript (funciones.. if ($impresos==3) { $proximo=$inicio+3.html): <script src="funciones. echo "<a href=\"pagina2. por lo que creamos un hipervínculo y pasamos como parámetro el valor de $inicio más 3. El archivo HTML es el siguiente (pagina1.js) es: .Cargar un control de tipo select Confeccionaremos un problema que contenga dos controles de tipo select. echo "<a href=\"pagina2.. } else echo "siguientes".php?pos=$proximo\" id=\"sig\">Siguientes</a>". 15 .js" language="JavaScript"></script> </head> <body> <h1>Prueba de cargar un control de tipo select recuperando datos del servidor mediante AJAX</h1> Seleccione la carrera: <select id="carreras" name="carreras"> <option value="0">Seleccionar.{ $anterior=$inicio-3."Telecomunicaciones" y "WebMaster") Cuando se seleccione una carrera enviaremos una petición al servidor para que retorne todas las materias que tiene esa carrera y procederemos a la carga del segundo select.. } Para el hipervínculo de "Siguientes" procedemos de forma similar.php?pos=$anterior\" id=\"ant\">Anteriores </a>". si $impresos vale 3 significa que posiblemente haya más registros que mostrar.

'load'. function mostrarMaterias(e) { var codigo=document. true). conexion1.length=0. op. var texto=document.getElementById('espera').getElementById('carreras').appendChild(texto).firstChild.getElementById('materias'). } } else { var d=document.f<pals. addEvent(select1. d.f++) { var op=document./cargando.length=0. var select2=document.length. function inicializarEventos() { var select1=document. } var conexion1.php?cod='+codigo.onreadystatechange = procesarEventos.mostrarMaterias.getElementById('carreras'). conexion1.false).send(null).addEvent(window.gif">'. conexion1. if (codigo!=0) { conexion1=crearXMLHttpRequest().getElementById('espera'). } } //*************************************** //Funciones comunes a todos los problemas ..innerHTML = '<img src=".options.readyState == 4) { var d=document.responseXML.inicializarEventos. select2.appendChild(op). select2. } } function procesarEventos() { if(conexion1. select2.false). for(f=0.getElementById('materias').getElementsByTagName('materia'). } else { var select2=document.innerHTML = ''. d.createElement('option').options.'pagina1.'change'. var xml = conexion1.createTextNode(pals[f].nodeValue). var pals=xml.open('GET'.value.

return true.php?cod='+codigo. conexion1.'pagina1.captura).attachEvent) { elemento.mostrarMaterias. . return xmlHttp. } else { var select2=document.addEventListener(nomevento.send(null).captura) { if (elemento.getElementById('carreras'). } En la primer función que se ejecuta luego de haberse cargado completamente la página definimos el evento change para el primer select: var select1=document.XMLHttpRequest) xmlHttp = new XMLHttpRequest().funcion).attachEvent('on'+nomevento. if (window. Es decir cuando hagamos la selección de un item del primer select se dispara la función mostrarMaterias.addEventListener) { elemento. return true. true).false).open('GET'.getElementById('materias'). } function crearXMLHttpRequest() { var xmlHttp=null.getElementById('carreras').onreadystatechange = procesarEventos. conexion1.//*************************************** function addEvent(elemento.XMLHTTP").funcion. if (codigo!=0) { conexion1=crearXMLHttpRequest() conexion1. La función mostrar materias: function mostrarMaterias(e) { var codigo=document.funcion. } else return false.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft.'change'. addEvent(select1. else if (window.nomevento. } else if (elemento.value.

readyState == 4) { var d=document. Como sabemos el archivo XML contiene un conjunto de materias: var pals=xml.getElementById('materias').length. . } } Rescata el valor del primer select (es decir donde estan almacenadas los nombres de carreras. La función procesarEventos: function procesarEventos() { if(conexion1..createTextNode(pals[f].options. En caso de seleccionar el primer item del select (contiene el texto "Seleccionar.options. op.nodeValue). var pals=xml. var xml = conexion1. var select2=document.. } } else { var d=document. select2. for(f=0.f<pals.getElementsByTagName('materia').firstChild.createElement('option')./cargando.innerHTML = '<img src=". } } Rescata el contenido del archivo XML retornado del servidor: var xml = conexion1. select2. op.f++) { var op=document.responseXML.getElementById('espera').nodeValue)..appendChild(texto).createElement('option'). select2..f++) { var op=document.gif">'.f<pals. var texto=document.length=0.getElementById('espera').appendChild(texto).length.length=0. Si está seleccionada procede a crear un objeto de tipo XMLHttpRequest y le pasa como parámetro el código de la carrera respectiva. Mediante un for las rescatamos y las agregamos al segundo select: for(f=0.appendChild(op).appendChild(op).responseXML.getElementsByTagName('materia').") procedemos a borrar el contenido del segundo select.firstChild.createTextNode(pals[f].innerHTML = ''. d. var texto=document.select2. d.

="</materias>\n". 'Estructura de las Organizaciones'.'Bases de Datos'). echo $xml.'Analisis Matematico'.'Sistemas de Comunicaciones I ').$f<count($materias). Luego generamos la estructura del archivo XML respectivo y disponemos en la cabecera de la petición que se trata de un archivo XML: header('Content-Type: text/xml'). header('Content-Type: text/xml'). } if ($car==2) { $materias=array('Fundamentos de Fisica'. echo $xml. 'Ingles Tecnico I'.php <?php $car=$_REQUEST['cod'].0\"?>\n".="<materia>". } $xml="<?xml version=\"1.$materias[$f]. 16 . $xml. if ($car==1) { $materias=array('Programacion I'.} Nos queda el programa que se ejecuta en el servidor para generar el archivo XML con las materias de la carrera seleccionada por el visitante (para facilitar el problema no hemos dispuesto esta información en una base de datos. } $xml. for($f=0.="<materias>\n".'Analisis Matematico 1'. } if ($car==3) { $materias=array('Informatica I'.$f++) { $xml.Mostrar un tooltip con datos recuperados del servidor en forma asincrónica .'Etica Profesional')."</materia>\n".'Multimedia I'. ?> Según el código de carrera se genera un vector $materias con todas las materias de esa carrera. pagina1.

inicializarEventos.css" type="text/css"> </head> <body> <p>Entre con el mouse al recuadro. El archivo HTML muestra un conjunto de div (cuadrados). visibility: hidden. Recordemos que un Tooltip es un mensaje que aparece sobre un objeto cuando disponemos la flecha del mouse sobre el mismo. cuando pasamos la flecha del mouse sobre el cuadrado aparecerá un mensaje. function inicializarEventos() { . } #divmensaje { background-color: yellow. margin:3px. padding: 5px.css: .js" type="text/javascript"></script> <link rel="StyleSheet" href="estilos. z-index: -1. position: absolute.</p> <div class="cuadradito" id="c1"></div> <div class="cuadradito" id="c2"></div> <div class="cuadradito" id="c3"></div> <div class="cuadradito" id="c4"></div> </body> </html> Luego tenemos el archivo estilos.js: addEvent(window. El archivo HTML es pagina1. este mensaje lo buscaremos en el servidor. width: 50px.false).Para aplicar varios de los conceptos vistos hasta ahora veamos una implementación de un Tooltip con DHTML y recuperando la información a mostrar del servidor en forma asincrónica. este recuadro nos informa el objetivo de dicho control. width:250px.cuadradito{ background-color: #f00. } El archivo funciones. z-index: 100.html: <html> <head> <title>Problema</title> <script languaje="javascript" src="funciones.'load'. height: 50px.

var vec=document.getElementsByTagName('div'); for(f=0;f<vec.length;f++) { addEvent(vec[f],'mouseover',mostrarToolTip,false); addEvent(vec[f],'mouseout',ocultarToolTip,false); addEvent(vec[f],'mousemove',actualizarToolTip,false); } var ele=document.createElement('div'); ele.setAttribute('id','divmensaje'); vec=document.getElementsByTagName('body'); vec[0].appendChild(ele); } function mostrarToolTip(e) { var d = document.getElementById("divmensaje"); d.style.visibility = "visible"; if (window.event) e=window.event; d.style.left = e.clientX + document.body.scrollLeft + 15; d.style.top = e.clientY + document.body.scrollTop + 15; var ref; if (window.event) ref=window.event.srcElement; else if (e) ref=e.target; recuperarServidorTooltip(ref.getAttribute('id')); } function actualizarToolTip(e) { if (window.event) e=window.event; var d = document.getElementById("divmensaje"); d.style.left = e.clientX + document.body.scrollLeft + 15; d.style.top = e.clientY + document.body.scrollTop + 15; } function ocultarToolTip(e) { var d = document.getElementById("divmensaje"); d.style.visibility = "hidden"; } var conexion1; function recuperarServidorTooltip(codigo) { conexion1=crearXMLHttpRequest(); conexion1.onreadystatechange = procesarEventos; conexion1.open('GET','pagina1.php?cod='+codigo, true); conexion1.send(null); }

function procesarEventos() { var d = document.getElementById("divmensaje"); d.style.visibility = "visible"; if(conexion1.readyState == 4) { d.innerHTML=conexion1.responseText; } else { d.innerHTML = '<img src="../cargando.gif">' ; } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento,nomevento,funcion,captura) { if (elemento.attachEvent) { elemento.attachEvent('on'+nomevento,funcion); return true; } else if (elemento.addEventListener) { elemento.addEventListener(nomevento,funcion,captura); return true; } else return false; } function crearXMLHttpRequest() { var xmlHttp=null; if (window.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); else if (window.XMLHttpRequest) xmlHttp = new XMLHttpRequest(); return xmlHttp; } Primero obtenemos la referencia a todos los div de la página: var vec=document.getElementsByTagName('div'); Definimos las funciones que se disparan para los eventos mouseover, mouseout y mousemove: for(f=0;f<vec.length;f++) {

addEvent(vec[f],'mouseover',mostrarToolTip,false); addEvent(vec[f],'mouseout',ocultarToolTip,false); addEvent(vec[f],'mousemove',mostrarToolTip,false); } Podemos ver que enlazamos la misma función para los eventos mouseover y mousemove, esto debido a que en dicha función mostramos el Tooltip en la coordenada actual del mouse. Por otro lado la función inicializarEventos crea un div y lo añade al árbol de objetos, este nos servirá para mostrar el mensaje: var ele=document.createElement('div'); ele.setAttribute('id','divmensaje'); vec=document.getElementsByTagName('body'); vec[0].appendChild(ele); La función mostrarTooltip obtiene la referencia del div que muestra el mensaje (hasta este momento está oculto) y cambia la propiedad visibility a "visible", luego llama a la función recuperarServidorTooltip(ref.getAttribute('id')). function mostrarToolTip(e) { var d = document.getElementById("divmensaje"); d.style.visibility = "visible"; if (window.event) e=window.event; d.style.left = e.clientX + document.body.scrollLeft + 15; d.style.top = e.clientY + document.body.scrollTop + 15; var ref; if (window.event) ref=window.event.srcElement; else if (e) ref=e.target; recuperarServidorTooltip(ref.getAttribute('id')); } La función ocultarTooTip solo oculta el div del mensaje. function ocultarToolTip(e) { var d = document.getElementById("divmensaje"); d.style.visibility = "hidden"; } La función recuperarServidorTooltip recibe el valor del atributo id del div donde se encuentra la flecha del mouse. Se crea un objeto de la clase XMLHttpRequest y se envía el código del div respectivo. var conexion1; function recuperarServidorTooltip(codigo) { conexion1=crearXMLHttpRequest(); conexion1.onreadystatechange = procesarEventos; conexion1.open('GET','pagina1.php?cod='+codigo, true); conexion1.send(null);

responseText. if ($_REQUEST['cod']=='c4') echo "<p>Cuarto tooltip.getElementById("divmensaje"). echo "aaaaaaaaaaaaaaaaaaa aaaaaaaaa aaaaaaaaaaaaa aaaaaaaaaaaaaaaa". pero para concentrarnos en lo esencial hemos dejado esto de lado. } if ($_REQUEST['cod']=='c3') echo "<p>Tercer tooltip.readyState == 4) { d.} Luego la función procesarEventos carga el div y procede hacerlo visible: function procesarEventos() { var d = document. echo "aaaaaaaaaaaaaaaaaaa aaaaaaaa aaaaaaaaaaaaaa aaaaaaaaa aaaaaaa". } if ($_REQUEST['cod']=='c2') { echo "<p>Segundo tooltip.</p>".style.php): <?php if ($_REQUEST['cod']=='c1') { echo "<p>Primer tooltip. if(conexion1.visibility = "visible".innerHTML = ' } } Por último el programa del servidor genera un trozo de HTML dependiendo del código de div enviado (pagina1. echo "aaaaaaaaaaaaaa aaaaa aaaaaaaaaaaaaaaaaaaaaa aaaaaa aaaaaaaaaa". echo "<p>aaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaa aaaaaa aaaaaaaaaa".innerHTML=conexion1. 17 . ?> En la realidad estos datos generalmente se rescatan de una base de datos.</p>".Autocompletar un control de tipo text . echo "aaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaa aaaaaaa aaaaaaaaaaaaaaaa</p>". echo "bbbbbbbb bbbbbbbbbb bbbbbbbbbbbb bbbbbbbbbb bbbbbbbbbbb bbb</p>". } else { d.</p>". echo "<p>bbbbbbbb bbbbbbbbbbb bbbbbbbb bbbbbbbbbbbbbb bbbbbbbbbbb bb".</p>". d. '.

A medida que tipiemos caracteres dentro de un control de tipo text mostraremos un conjunto de palabras que comienzan con los caracteres ingresados hasta el momento.css" type="text/css"> La hoja de estilo es estilos.css: #resultados { position:absolute. En la realidad los datos se extraen de una base de datos pero para simplificar el problema no lo haremos en este caso. } Es importante notar que la clase #resultados hemos definido la propiedad position con el valor absolute. Veremos los distintos archivos que intervienen para solucionar el problema: pagina1.css" type="text/css"> </head> <body> <form action="#"> Ingrese una palabra que comience con a:<br> <input type="text" id="palabra" autocomplete="off"><br> <div id="resultados"></div> <input type="submit" value="buscar"> </form> </body> </html> Este página no tiene nada nuevo.Implementaremos con AJAX el concepto de autocompletar o también conocido como lista de sugerencias.false). function inicializarEventos() .inicializarEventos.'load'.js addEvent(window. Es importante notar que hemos dispuesto los elementos para incorporar la hoja de estilo y el archivo donde se encuentran las funciones en JavaScript: <script languaje="javascript" src="funciones.js" type="text/javascript"></script> <link rel="StyleSheet" href="estilos. Esto significa que el cuadro donde aparecerá la lista de palabras estará superpuesta a otro contenido de la página.html <html> <head> <title>Problema</title> <script languaje="javascript" src="funciones.js" type="text/javascript"></script> <link rel="StyleSheet" href="estilos. El archivo funciones. Además el color de fondo es amarillo. background:#ff0.

for(f=0.value. } var conexion1.{ var ob=document. } function procesarEventos() { var resultados = document. conexion1.funcion). } else { resultados.presionTecla.innerHTML = resultados.getElementById('palabra'). function presionTecla(e) { conexion1=crearXMLHttpRequest().getElementsByTagName('palabra').responseXML.nodeValue + '<br>'.funcion.firstChild. true). var pals=xml.f++) { resultados. } } else alert(conexion1.onreadystatechange = procesarEventos.statusText).readyState == 4) { if (conexion1. return true. } '.nomevento. if(conexion1. addEvent(ob. palabra=document. .captura) { if (elemento.f<pals. resultados.false).innerHTML + pals[f].innerHTML=''.'pagina1.'keyup'.length.attachEvent) { elemento.getElementById("resultados").send(null).open('GET'.attachEvent('on'+nomevento.php?palabra='+palabra. conexion1.innerHTML = ' } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento. conexion1.status==200) { var xml = conexion1.getElementById('palabra').

return xmlHttp. } En la función inicializarEventos: var ob=document.readyState == 4) { if (conexion1.send(null).false). addEvent(ob.XMLHTTP"). if(conexion1. Enlazamos la función presionTecla para cuando ocurre el evento keyup del único control text que contiene la página.open('GET'.onreadystatechange = procesarEventos. } function crearXMLHttpRequest() { var xmlHttp=null. al momento de soltarla se ejecuta la función presionTecla. } crea un objeto de la clase XMLHttpRequest. conexion1. return true. Es decir que cada vez que el usuario presione una tecla. if (window. true).addEventListener) { elemento.addEventListener(nomevento.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft.getElementById("resultados").'pagina1. else if (window. } else return false. function presionTecla(e) { conexion1=crearXMLHttpRequest().status==200) .value.XMLHttpRequest) xmlHttp = new XMLHttpRequest().getElementById('palabra'). La función presionTecla: var conexion1.presionTecla. palabra=document.getElementById('palabra').'keyup'.else if (elemento.php?palabra='+palabra. conexion1. Luego la función procesarEventos: function procesarEventos() { var resultados = document. conexion1.captura).funcion. extrae el contenido del text y procede a efectuar la petición al servidor pasando mediante el método GET la cadena ingresada hasta ese momento.

length.statusText). $xml.innerHTML=''.'abrir').0.innerHTML = resultados.'animo'. if (isset($veciguales)) { for($f=0.f<pals.="<palabra>". . $vec=array('alma'.'aro'.'amo'.$f<count($vec). } } else alert(conexion1. header('Content-Type: text/xml').innerHTML = ' } } Cuando la propiedad readyState informa que llegaron todos los datos y además la propiedad status retorna un 200 procedemos a rescatar los datos mediante la propiedad responseXML.f++) { resultados.$f++) { if ($pal==substr($vec[$f]. var pals=xml. } } $xml="<?xml version=\"1.$f<count($veciguales).'arbol'.{ var xml = conexion1.'algo'."</palabra>\n".firstChild.$f++) { $xml.getElementsByTagName('palabra').responseXML.0\"?>\n". if (strlen($pal)>0) { for($f=0. for(f=0. Nos queda el archivo que se ejecuta en el servidor y nos retorna el archivo XML con la lista de palabras (pagina1.nodeValue + '<br>'.="<palabras>\n". } } $xml.$veciguales[$f]. resultados. Por último procedemos a mostrar la lista de palabras dentro del div resultados.="</palabras>\n". echo $xml. ?> '. } else { resultados.strlen($pal))) $veciguales[]=$vec[$f].php): <?php $pal=$_REQUEST['palabra'].innerHTML + pals[f].

strlen($pal))) $veciguales[]=$vec[$f].'aro'. 18 .$f++) { $xml. } } $xml.$veciguales[$f].'abrir').Encuenta con AJAX Confeccionaremos un nuevo problema donde podemos utilizar AJAX.php" method="post" id="formulario"> <fieldset> <h2>Que lenguaje utiliza para la implementación de páginas ."</palabra>\n".Las palabras las tenemos en un vector (en la realidad generalmente se extraen de una base de datos): $vec=array('alma'. La característica principal es que cuando el operador haga su selección procederemos a enviar la selección al servidor y generaremos un gráfico en forma dinámica en el servidor y procederemos a actualizar en forma asincrónica solo una parte de la página. pagina1.="</palabras>\n".0. if (isset($veciguales)) { for($f=0. $xml. } Generamos una cadena cuyo contenido es XML: $xml="<?xml version=\"1.0\"?>\n". Almacenamos en un vector todas las que comienzan con la cadena ingresada hasta el momento: for($f=0.$f++) { if ($pal==substr($vec[$f].'amo'.$f<count($vec).'algo'.</h1> <form action="pagina1.="<palabras>\n".'arbol'.php <body> <h1>Implementación de una encuesta empleando AJAX. Y por último indicamos la información a enviar: echo $xml. Informamos al navegador que enviaremos un archivo XML: header('Content-Type: text/xml'). Vamos a desarrollar una pequeña aplicación para hacer una encuesta.="<palabra>".'animo'.$f<count($veciguales).

getElementById('radio2').event.onreadystatechange = procesarEventos. conexion1. addEvent(ref. conexion1. } function procesarEventos() { .'pagina1. } function enviarDatos(e) { if (window.event) window.getElementById('radio1').checked) enviarSeleccion(3).'load'.false).preventDefault(). else if (document.js addEvent(window.returnValue=false. function inicializarEventos() { var ref=document. else if (e) e. conexion1. if (document.open('GET'.getElementById('radio3').enviarDatos. else if (document.'submit'.php?codigo='+cod+"&aleatorio="+aleatorio.inicializarEventos.checked) enviarSeleccion(2). true).send(null).dinámicas?</h2> <div id="encuesta"> <input type="radio" id="radio1" name="radio">PHP<br> <input type="radio" id="radio2" name="radio">ASP<br> <input type="radio" id="radio3" name="radio">JSP<br> <input type="submit" value="Enviar" id="enviar"> </fieldset> </div> </form> </body> </html> funciones.false).random().getElementById('formulario'). var aleatorio=Math.checked) enviarSeleccion(1). function enviarSeleccion(cod) { conexion1=crearXMLHttpRequest(). } var conexion1.

} function crearXMLHttpRequest() { var xmlHttp=null.getElementById("encuesta").funcion. if (window.addEventListener(nomevento. } Procedemos a capturar el evento submit para enviar los datos en forma asincrónica: function inicializarEventos() { var ref=document. . return true.captura) { if (elemento.attachEvent) { elemento.addEventListener) { elemento.funcion. } else if (elemento.XMLHTTP").'submit'. return true.captura). return xmlHttp. addEvent(ref. //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.readyState == 4) { encuesta.funcion).getElementById('formulario').var encuesta = document.attachEvent('on'+nomevento. if(conexion1.XMLHttpRequest) xmlHttp = new XMLHttpRequest(). '.enviarDatos.false). } else return false.innerHTML = ' } else { encuesta.innerHTML = ' } } '.nomevento.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. else if (window.

.getElementById('radio3').readyState == 4) { encuesta. true).getElementById("encuesta").returnValue=false.'pagina1. else if (e) e.random().checked) enviarSeleccion(1).getElementById('radio2').onreadystatechange = procesarEventos.open('GET'. function enviarSeleccion(cod) { conexion1=crearXMLHttpRequest().send(null). else if (document. '.} Cuando se presiona el botón submit procedemos a llamar a la función enviarSeleccion con el número de opción seleccionada: function enviarDatos(e) { if (window. conexion1. Esto se hace cuando el objeto XMLHttpRequest nos informa que los datos fueron generados completamente: function procesarEventos() { var encuesta = document. if(conexion1. if (document. } La función procesarEventos carga la imagen generada dinámicamente en el servidor.preventDefault().event) window. } La función enviarSeleccion procede a crear un objeto de la clase XMLHttpRequest y envía el número de opción seleccionada de la encuesta y un valor aleatorio para que no rescate el navegador una página que se encuentre en la cache de la computadora: var conexion1.event.checked) enviarSeleccion(2).php?codigo='+cod+"&aleatorio="+aleatorio.getElementById('radio1'). conexion1. conexion1.innerHTML = ' } } '.innerHTML = ' } else { encuesta. else if (document. var aleatorio=Math.checked) enviarSeleccion(3).

$conexion) or die("Problemas en el select:"."z80") or die("Problemas en la conexion").Por último el archivo pagina1. $registro=mysql_query("select * from encuesta where codigo=1". class Barra { var $ancho.$conexion) or die("Problemas en el select:".mysql_error()). var $alto. $barra->sumar($reg['pregunta1']. $barra->sumar($reg['pregunta3'].mysql_error()). } function fijarcolorfondo($rojo. var $colorvalores. mysql_select_db("bdajax". var $imagen.$conexion) or die(mysql_error()).$titulo) { $indice=count($this->datos). if ($preg==3) $registros=mysql_query("update encuesta set pregunta3=pregunta3+1 where codigo=1".$verde. $barra->graficar()."JSP"). $barra->sumar($reg['pregunta2']."ASP"). if ($preg==2) $registros=mysql_query("update encuesta set pregunta2=pregunta2+1 where codigo=1". $this->datos[$indice]['valor']=$valor. function sumar($valor. $reg=mysql_fetch_array($registro). var $vectorcolorbarra. var $colorbarra. var $colorfondo."root". $conexion=mysql_connect("localhost". $barra=new Barra(500.$conexion) or die("Problemas en la seleccion de la base de datos").mysql_error()). //almacena los valores y los titulos de cada barra var $datos."PHP").$azul) { . var $vectorcolorfondo. $this->datos[$indice]['titulo']=$titulo. $barra->fijarprofundidad(20).$conexion) or die("Problemas en el select:". var $profundidad.php <?php $preg=$_REQUEST['codigo']. if ($preg==1) $registros=mysql_query("update encuesta set pregunta1=pregunta1+1 where codigo=1".300).

foreach ($this->datos as $val) { if ($primera) { $primera=false. $this->vectorcolorfondo[1]. $this->vectorcolorfondo[2]=$azul. if ($verde<0) $verde=0. . ImageFill($this->imagen. $puntos[]=$columna. $may=0.$y1.$this->vectorcolorbarra[2]).$y2) { $rojo=$this->vectorcolorbarra[0]-90. } return $may. $this->colorbarra=ImageColorAllocate($this->imagen. } if ($val['valor']>$may) $may=$val['valor']. $colorsombra=imageColorAllocate($this->imagen.$rojo. } //Metodo privado function mayor() { $primera=true. $this->colorfondo=ImageColorAllocate ($this->imagen.$this->vectorcolorfondo[0].0. } function fijarcolorbarra($rojo.$this->colorfondo). if ($rojo<0) $rojo=0. $may=$val['valor'].0. $azul=$this->vectorcolorbarra[2]-90. $this->vectorcolorbarra[2]=$azul. $this->vectorcolorbarra[1]=$verde. $puntos[]=$y1.$this->vectorcolorbarra[0].$azul) { $this->vectorcolorbarra[0]=$rojo.$this->vectorcolorfondo[2]). $verde=$this->vectorcolorbarra[1]-90. } function fijarprofundidad($profundidad) { $this->profundidad=$profundidad.$azul). } function graficarsombraizquierda($columna. $this->vectorcolorfondo[1]=$verde.$verde. if ($azul<0) $azul=0. $this->vectorcolorbarra[1].$this->vectorcolorfondo[0]=$rojo.$verde.

$colorbordebarra).$azul).$this->vectorcolorbarra[0].4. $azul=$this->vectorcolorbarra[2]-40. imagefilledpolygon($this->imagen. $puntos[]=$y2-$this->profundidad.0. $this->vectorcolorfondo[0]=0. . $colorbordebarra=imageColorAllocate($this->imagen.4.0). $this->vectorcolorbarra[0]=255.$this->vectorcolorfondo[0].$alto) { $this->ancho=$ancho.$this->vectorcolorfondo[2]). $this->colorfondo=ImageColorAllocate($this->imagen. $puntos[]=$y1-$this->profundidad. $puntos[]=$columna+$this->profundidad.$puntos[]=$columna.$puntos. $this->profundidad=10.$colorbordebarra). $puntos[]=$columna. } function graficarsombrasuperior($columna. $colorsombra=imageColorAllocate($this->imagen. $puntos[]=$y1.0. $verde=$this->vectorcolorbarra[1]-40.0.$colorsombra). $this->vectorcolorbarra[1]=255.$puntos. imagepolygon($this->imagen. imagefilledpolygon($this->imagen. $this->vectorcolorfondo[1].$this->alto). $puntos[]=$y2. $colorbordebarra=imageColorAllocate($this->imagen. } function Barra($ancho.$puntos.$anchobarra) { $rojo=$this->vectorcolorbarra[0]-40.$verde. $this->vectorcolorbarra[2]=0.0).4. imagepolygon($this->imagen. $puntos[]=$y1-$this->profundidad. $puntos[]=$y1. $this->colorbarra=ImageColorAllocate($this->imagen.$rojo. $puntos[]=$columna+$this->profundidad. if ($azul<0) $azul=0. $puntos[]=$columna+$anchobarra+$this->profundidad.$this->vectorcolorbarra[2]).0.$colorsombra). ImageFill($this->imagen. $this->vectorcolorfondo[2]=255.0. $this->alto=$alto.4. $this->vectorcolorbarra[1]. $this->imagen=imageCreate($this->ancho.$y1. $puntos[]=$columna+$this->profundidad. $puntos[]=$columna+$anchobarra. $this->vectorcolorfondo[1]=0. $puntos[]=$y1-$this->profundidad. if ($verde<0) $verde=0.0. if ($rojo<0) $rojo=0.$puntos.$this->colorfondo).

es decir remplaza a XML o el envío de texto plano.$x1+$anchobarra.$y1-$altura+5. Este formato de datos es más liviano que XML. } Header ("Content-type: image/png").$this->colorbarra). ImageString($this->imagen. $barra->fijarprofundidad(20).$y1.$reg['titulo']. $x1=10.$x1. $barra->graficar().0.$y1.$y1$altura. } function graficar() { $may=$this->mayor(). $anchobarra=($this->ancho-110)/count($this->datos). imagerectangle($this->imagen.$y1). ImagePNG ($this->imagen.$x1+3.png"). ImageDestroy($this->imagen). Básicamente la clase Barra nos permite crear un gráfico de barra creando un objeto de dicha clase y pasando los datos respectivos: $barra=new Barra(500.$colorbordebarra).2.$y1-$altura.0).$y1-$altura.$x1+3. $barra->sumar($reg['pregunta3']."PHP").2.0.$y1-$altura. imagefilledrectangle($this->imagen.$this>colorbarra).$this->colorvalores=ImageColorAllocate($this->imagen. $colorbordebarra=imageColorAllocate($this->imagen. } } ?> No analizaremos mucho este archivo ya que no es objetivo del curso el aprendizaje de PHP."ASP").$x1.$this>colorvalores). . $this->graficarsombrasuperior($x1.300).Qué es JSON? JSON es el acrónimo de JavaScript Object Notation."encuesta.0. ImageString($this->imagen. 19 . $x1=$x1+$anchobarra+(100/count($this->datos))."JSP").0).$x1+$anchobarra. foreach($this->datos as $reg) { $altura=($reg['valor']/$may)*($this->alto-80).0. $y1=$this->alto-50.$anchobarra).$y1. JSON es un formato alternativo de envío y recepción de datos. $barra->sumar($reg['pregunta2']. $barra->sumar($reg['pregunta1'].$reg['valor']. $this->graficarsombraizquierda($x1+$anchobarra.

Cuando definimos un array literal no le indicamos a cada elemento de que tipo se trata.26]. Los objetos literales se definen por medio de pares "nombre":"valor" Todo objeto literal tiene un nombre.false) y el valor null. en el ejemplo le llamé persona. Para acceder a las propiedades del objeto literal lo podemos hacer de dos formas: alert(persona. podemos almacenar cadenas (entre comillas). 'edad':22.'secundario'] }. //Imprimimos el primer elemento del array alert(usuario[1]). Tenemos que repasar un poco como se definen los array literales y objetos literales en JavaScript. Todas las propiedades del objetos se encuentran encerradas entre llaves. valores lógicos (true. números. Y por último cada propiedad se las separa de las otras propiedades por medio de la coma. Como vemos los elementos de un array literal se encierran entre corchetes y los valores contenidos van separados por coma. . Para acceder a los elementos de un array literal lo hacemos por su nombre y entre corchetes indicamos que elementos queremos acceder: alert(usuario[0]). //Imprimimos el segundo elemento del array Veamos como definimos los objetos literales en JavaScript: var persona={ 'nombre':'juan'. Luego cada propiedad y valor se las separa por dos puntos. //Imprime el valor de la propiedad nombre del La segunda forma es indicando la propiedad entre corchetes: alert(persona['nombre']).Veremos que hace el código más sencillo ya que utiliza el código JavaScript como modelo de datos. 'clave':'xyz'. Un objeto literal contiene una serie de propiedades con sus respectivos valores. ya que serán las estructuras para la transmisión de datos: var usuario=['juan'. Luego se pueden combinar objetos literales y array literales: var persona={ 'nombre':'juan'.nombre). objeto persona. 'edad':26 }. 'estudios':['primario'.

sino directamente indicamos entre llaves las propiedades y sus valores.nombre). alert(persona. 'edad':22. Tambien hemos eliminado el punto y como luego de la llave final. El resto es igual.estudios[1]). 'estudios':['primario'. como vimos si se trata de un archivo XML llamamos al método requestXML y luego accedemos por medio del DOM . 'edad':22.'secundario'] } Podemos ver que es mucho más directa la definición de esta estructura (de todos modos cuando la estructura a representar es muy compleja XML sigue siendo la opción principal) Como podemos ver si tenemos que transmitir estas estructuras por internet la notación JSON es más liviana.Como podemos ver podemos crear estructuras de datos complejas combinando objetos literales y array literales. alert(persona. Otra ventaja es como recuperamos los datos en el navegador.estudios[0]). Luego para acceder a los distintos elementos tenemos: alert(persona. Ahora veamos la diferencia entre JSON y XML utilizando este ejemplo: XML: <persona> <nombre>juan</nombre> <edad>22</edad> <estudios> <estudio>primario</estudio> <estudio>secundario</estudio> </estudios> </persona> Y como vimos en JSON: { 'nombre':'juan'. 'estudios':['primario'.'secundario'] } Como podemos ver en la sintaxis JSON no aparecen variables. La sintaxis de JSON difiere levemente de lo visto anteriormente: { 'nombre':'juan'.

microprocesador)." + " 'discos':[80.'load'.inicializarEventos. alert('Memoria ram:'+maquina.html <html> <head> <title>Problema</title> <script src="funciones. capacidad de cada disco duro) Mostrar los datos mediante el método alert Hay que tener bien en cuenta que en este problema no hay nada de AJAX ya que no nos comunicaremos con el servidor para el envío de datos." + " 'memoria':1024. memoria ram.false). pagina1. var maquina=eval('(' + cadena + ')'). } function presionBoton(e) { var cadena="{ 'microprocesador':'pentium'.responseText + ')'). El objeto literal debe representar las características de una computadora (procesador. function inicializarEventos() { var ob=document.false).presionBoton.En cambio con JSON al llegar el archivo procedemos a generar una variable en JavaScript que recree el objeto literal.getElementById('boton1').'click'. esto mediante la función eval: var persona=eval('(' + conexion1. Ya veremos en el próximo concepto como recuperar los datos del servidor mediante el objeto XMLHttpRequest Para probar y generar un objeto a partir de una notación JSON haremos el siguiente problema: Confeccionar una página que contenga un botón. addEvent(ob.250]" + " }".js" language="JavaScript"></script> </head> <body> <h1>Evaluar una variable que contiene notación JSON. alert('microprocesador:'+maquina. .js addEvent(window.memoria). Al ser presionado evaluar un string que almacena un objeto literal con notación JSON.</h1> <input type="button" id="boton1" value="Ver"> </body> </html> funciones.

memoria).captura).funcion)." + " 'memoria':1024. } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.captura) { if (elemento.funcion.discos[1]). En esta lo primero que hacemos definimos un string que contiene un objeto con notación JSON: var cadena="{ 'microprocesador':'pentium'. Esto se logra utilizando la función eval de JavaScript.attachEvent('on'+nomevento. alert('Capacidad disco 2:'+maquina.discos[0]). } Cuando se presiona el botón se ejecuta la función presionBoton. 20 .funcion.discos[0]). alert('Capacidad disco 1:'+maquina. } else return false. alert('Memoria ram:'+maquina." + " 'discos':[80. Seguidamente pasamos a evaluar este string: var maquina=eval('(' + cadena + ')'). Es importante que siempre al string que contiene la notación JSON le debemos anteceder el paréntesis de apertura y finalizarlo con el paréntesis de cerrado (esto para que JavaScript no tenga problemas con las llaves de apertura y cierre de la notación JSON.nomevento.microprocesador). Una vez que tenemos el objeto en JavaScript procedemos a acceder a sus atributos: alert('microprocesador:'+maquina.addEventListener(nomevento. alert('Capacidad disco 2:'+maquina.addEventListener) { elemento.attachEvent) { elemento. return true.250]" + " }". return true.discos[1]).alert('Capacidad disco 1:'+maquina. } else if (elemento.Recuperar datos del servidor en formato JSON . Ahora si tenemos un objeto JavaScript.

'pagina1. function recuperarDatos(dni) { conexion1=crearXMLHttpRequest().false). } function presionBoton(e) { var ob=document. recuperarDatos(ob. Para reducir el tamaño del problema y concentrarnos en la forma de transmisión de datos y su posterior recuperación en el navegador no implementaremos una base de datos en el servidor (en la realidad los datos de los votantes se encontrarían en una tabla) El archivo pagina1.html: <html> <head> <title>Problema</title> <script src="funciones. } var conexion1.Para ver como recuperamos datos del servidor en formato JSON en lugar de texto plano o XML implementaremos el siguiente ejemplo: Confeccionar un sitio que permita ingresar el documento de una persona y nos retorne su apellido.send(null).inicializarEventos. conexion1.2 y 3):<input type="text" name="dni" id="dni" size="10"><br> <input type="button" value="Enviar" id="boton1"> <div id="resultados"></div> </body> </html> El archivo html no tiene nada especial. El archivo funciones. .js" language="JavaScript"></script> </head> <body> Ingrese dni (solo existen los valores 1. nombre y lugar donde debe votar.'load'.value).false). Definimos el div resultados para mostrar posteriormente los datos devueltos por el servidor.onreadystatechange = procesarEventos.'click'. function inicializarEventos() { var ob=document. addEvent(ob. true). conexion1.getElementById('dni'). conexion1.js: addEvent(window.getElementById('boton1').open('GET'.php?dni='+dni.presionBoton.

. } else if (elemento. else if (window. } function crearXMLHttpRequest() { var xmlHttp=null..innerHTML = salida.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. return xmlHttp. } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.nomevento. } Cuando se presiona el botón enviar se ejecuta la función: . if (window.readyState == 4) { var datos=eval("(" + conexion1. salida=salida+"Nombre:"+datos.addEventListener) { elemento.addEventListener(nomevento.XMLHttpRequest) xmlHttp = new XMLHttpRequest().responseText + ")").attachEvent) { elemento.nombre+"<br>". return true. } else { resultados.attachEvent('on'+nomevento. salida=salida+"Dirección donde debe votar:"+datos.direccion.".getElementById("resultados"). var salida = "Apellido:"+datos. return true. resultados.funcion.apellido+"<br>". if(conexion1.captura). } else return false.} function procesarEventos() { var resultados = document.funcion).funcion.captura) { if (elemento.XMLHTTP").innerHTML = "Cargando.

La función: var conexion1. } crea un objeto de la clase XMLHttpRequest y procede a realizar una comunicación asincrónica con el servidor pasando por parámetro GET el dni ingresado por el visitante al sitio. conexion1. Como podemos observar es muy fácil acceder luego a la información devuelta por el servidor. } En esta función recuperamos el documento ingresado por el operador y llamamos a la función recuperarDatos pasando como parámetro el dni de la persona. Por último el archivo pagina1.function presionBoton(e) { var ob=document. Procedemos mediante la función eval a generar un objeto en JavaScript y posteriormente mostramos los datos accediendo a los atributos de dicho objeto. charset=ISO-8859-1').apellido+"<br>". resultados.getElementById('dni').open('GET'.'pagina1. true). } else { resultados.responseText + ")"). recuperarDatos(ob. salida=salida+"Dirección donde debe votar:"+datos.nombre+"<br>". salida=salida+"Nombre:"+datos. . } } Cuando la propiedad readyState tiene almacenado un 4 procedemos a recuperar el string devuelto por la conexión como veremos un poco más abajo se trata de un string que almacena los datos en formato JSON. function recuperarDatos(dni) { conexion1=crearXMLHttpRequest().php: <?php header('Content-Type: text/txt.onreadystatechange = procesarEventos. if(conexion1. conexion1.getElementById("resultados")..". conexion1. Luego la función procesarEventos se ejecuta para cada uno de los estados de la petición: function procesarEventos() { var resultados = document..innerHTML = salida.value). var salida = "Apellido:"+datos.readyState == 4) { var datos=eval("(" + conexion1.php?dni='+dni.direccion.innerHTML = "Cargando.send(null).

'direccion':'$direccion' }". $apellido='Rodriguez'. 'apellido':'$apellido'.php) En el concepto anterior habíamos visto como generar un archivo con formato JSON en el servidor y enviárselo al cliente (navegador). $direccion=''. 'apellido':'$apellido'. Esta metodología de generar el string con formato JSON puede ser muy engorroso cuando las estructuras comienzan a ser más complejas. Lo más interesante es como procedemos a generar la salida con formato JSON: echo "{ 'nombre':'$nombre'. . } if ($_REQUEST['dni']=='3') { $nombre='laura'. if ($_REQUEST['dni']=='1') { $nombre='Juan'.De PHP a JSON (utilizando la librería JSON. $direccion='Laprida 785'. Por medio de tres if verificamos que número de documento se trata y procedemos a inicializar tres variables. $direccion='Colon 123'. ?> Como dijimos para concentrarnos en JSON no extraemos la información de una base de datos. } if ($_REQUEST['dni']=='2') { $nombre='Ana'. $direccion='Lima 245'. $apellido='Maldonado'. 'direccion':'$direccion' }". 21 . Recordemos que todo objeto JSON debe ir entre llaves y cada atributo le debe seguir el caracter dos puntos y el valor de dicho atributo.$nombre=''. $apellido='Pueyrredon'. $apellido=''. } echo "{ 'nombre':'$nombre'.

while ($reg=mysql_fetch_array($registros)) { $vec[]=$reg. echo $cad. Para ver esta librería llamada JSON.descripcion."root"./JSON. $cad=$json->encode($vec).php: <?php $conexion=mysql_connect("localhost".php</h2> <br> <input type="button" value="Recuperar" id="boton1"> <div id="resultados"></div> </body> </html> Este archivo no tiene nada nuevo. El problema que resolveremos es el siguiente: Se tiene una tabla llamada "perifericos" donde almacenamos el código..php'). } require('.$conexion) or die("Problemas en la seleccion de la base de datos"). Generar un archivo JSON en el servidor y proceder a mostrar los datos de los periféricos en el navegador.html: <html> <head> <title>Problema</title> <script src="funciones. mysql_select_db("bdajax". .precio from perifericos". Lo más interesante y nuevo se presenta en el archivo pagina1.php confeccionaremos un problema que rescate un conjunto de registros de una tabla MySQL y seguidamente los transforme en formato JSON. Como podemos observar mientras sea más compleja la estructura a generar. pagina1. $json=new Services_JSON().$conexion) or die("Problemas en el select". descripción y precio de distintos periféricos de computadoras.mysql_error()). más propenso a errores será la generación. $registros=mysql_query("select codigo. En el navegador mediante eval generaremos un vector JavaScript y procederemos a mostrarlo."z80") or die("Problemas en la conexion").js" language="JavaScript"></script> </head> <body> <h2>Recuperar datos del servidor almacenados en una base de datos en formato JSON utilizando la librería JSON.Se cuenta con una clase que transforma vectores y clases de PHP a formato JSON en forma automática.

echo $cad. Luego el archivo JavaScript es: addEvent(window.="{'codigo':'".'load'.=']'. while ($reg=mysql_fetch_array($registros)) { $cad."."..inicializarEventos.php" y crear un objeto de la clase services_JSON: require('.php'). El archivo yo lo almacené en una carpeta que se encuentra inmediatamente en el nivel superior./ Luego el método que automáticamente convierte el vector PHP en formato JSON es: $cad=$json->encode($vec).?> Lo primero que hacemos es guardar todos los registros de la tabla perifericos en el vector llamado $vec. Este metodología es engorrosa y propensa a errores.="'descripcion':'". } $cad.$reg['precio']. . Procedemos seguidamente a la salida de esta cadena: echo $cad. function inicializarEventos() { var ob=document. Ahora ya tenemos en la variable $cad el contenido del vector en formato JSON.. Tengamos en cuenta que las cuatro líneas presentadas anteriormente nos evitan tener que generar la cadena en formato JSON en forma manual como podemos ver seguidamente: $cad='['.$reg['descripcion']."'. $cad.getElementById('boton1'). por eso la sintaxis . } Ahora debemos incluir el archivo llamado "JSON./JSON.$reg['codigo'].false).". $json=new Services_JSON(). esto mediante el ciclo: while ($reg=mysql_fetch_array($registros)) { $vec[]=$reg."'."'}. $cad.="'precio':'".

codigo+"<br>".onreadystatechange = procesarEventos. salida += 'Descripcion:'+datos[f].f++) { salida += 'Codigo:'+datos[f].. return true.attachEvent('on'+nomevento. } resultados. true).addEventListener) { elemento.readyState == 4) { alert('Cadena en formato JSON: '+conexion1. } else { resultados.open('GET'.php'.responseText). if(conexion1.f<datos.funcion.responseText + ")").descripcion+"<br>".addEvent(ob.funcion.false).getElementById("resultados").captura) { if (elemento.captura). } function procesarEventos() { var resultados = document. for(f=0. } else return false. function presionBoton(e) { conexion1=crearXMLHttpRequest(). } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.nomevento.'pagina1. . salida += 'Precio:'+datos[f]. return true. conexion1.attachEvent) { elemento. } var conexion1.'click'.funcion).presionBoton. conexion1.addEventListener(nomevento.length. } else if (elemento.innerHTML = "Cargando. var datos=eval("(" + conexion1. conexion1.precio+"<br><br>".. var salida=''.send(null).".innerHTML = salida.

Ahora sí mediante el comando eval procedemos a generar un vector JavaScript y mostramos los datos dentro de un div: var datos=eval("(" + conexion1.} function crearXMLHttpRequest() { var xmlHttp=null.js) Ahora veremos otra librería. var salida=''.precio+"<br><br>". pero hay muchas situaciones que necesitamos recuperar una estructura de datos del servidor y proceder a su procesamiento en el navegador.responseText). Podemos ver que se trata de un string JSON correctamente formado. salida += 'Precio:'+datos[f].length. if (window.js Solo debemos descargarla y agregarla en nuestra página.f++) { salida += 'Codigo:'+datos[f].codigo+"<br>". } resultados.responseText + ")"). Así de modo inverso nos permite generar un objeto o array JavaScript a partir de un string JSON y esto de modo seguro.descripcion+"<br>".XMLHTTP"). la misma nos permite convertir un objeto o array de JavaScript en formato JSON. for(f=0. Es decir que para hacer uso en estos ejemplos debemos tipear: .XMLHttpRequest) xmlHttp = new XMLHttpRequest(). salida += 'Descripcion:'+datos[f].innerHTML = salida. Esta librería se encuentra en json. 22 . Para este problema posiblemente es más fácil generar un trozo de HTML en el servidor y en el navegador solo mostrarlo.De JavaScript a JSON (utilizando la librería json.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. pero esta librería es en JavaScript. Para poder probarlos en este sitio yo la incorporé en una carpeta que se encuentra inmediatamente en el nivel superior donde se almacenan las páginas que está probando. return xmlHttp. } La función procesarEventos rescata los datos envidos por el servidor y los muestra inicialmente tal como llegan en una ventana mediante el comando alert: alert('Cadena en formato JSON: '+conexion1. else if (window.f<datos.

false).js" language="JavaScript"></script> Nuestro archivo con las funciones en JavaScript (funciones.1700.inicializarEventos. } //*************************************** .<script src=". Luego convertimos dicho objeto a formato JSON con un método contenido en la librería json.mostrarConversion... var cadena=obj.1990] }./json.js. edad:25.js" language="JavaScript"></script> <script src="funciones.. pagina1./json. addEvent(ref. alert(cadena).getElementById('boton1'). Para esto implementaremos un pequeño ejercicio donde al presionar un botón definimos un objeto que almacena tres atributos.js" language="JavaScript"></script> <script src="funciones.js" language="JavaScript"></script> </head> <body> <h2>Convertir un objeto JavaScript a formato JSON</h2> <input type="button" value="Convertir" id="boton1"> </body> </html> Es importante notar que hemos insertado dos archivos externos codificados en JavaScript: <script src=". } function mostrarConversion(e) { var obj={ nombre:'juan'.'click'.html: <html> <head> <title>Problema</title> <script src=".js" language="JavaScript"></script> La primera función que veremos es la que nos permite convertir un objeto o array a una cadena JSON. sueldos:[1200. function inicializarEventos() { var ref=document.js): addEvent(window. de los cuales uno es una array.toJSONString().'load'.false)./json.

alert(cadena).nomevento. } Lo más importante lo podemos encontrar en la función mostrarConversion: function mostrarConversion(e) { var obj={ nombre:'juan'. sueldos:[1200.captura).1700.toJSONString(). } Primero definimos un objeto en JavaScript: var obj={ nombre:'juan'. edad:25.addEventListener(nomevento.1700. edad:25.1990] }. } else return false.//Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.attachEvent) { elemento. de los cuales el último es un array con tres elementos.captura) { if (elemento.funcion. sueldos:[1200. 23 . alert(cadena).edad y sueldo).js) . } else if (elemento.funcion).addEventListener) { elemento. El objeto obj contiene tres atributos (nombre.funcion.toJSONString(). return true. var cadena=obj.1990] }. Luego simplemente llamando al método toJSONString retorna un string con el contendio del objeto pero codificado en formato JSON: var cadena=obj. return true.De JSON a JavaScript (utilizando la librería json.attachEvent('on'+nomevento.

false).js: <script src=".js</h2> <br> <input type="button" value="Recuperar" id="boton1"> <div id="resultados"></div> </body> </html> Es importante importar la librería json.js debemos hacer: var datos=conexion1.html <html> <head> <title>Problema</title> <script src="..inicializarEventos.js para convertir el archivo JSON a JavaScript. Tengamos en cuenta si el archivo JSON proviene de un sitio que no tenemos la seguridad que nos envíe solo objetos y array literales. Hay una solución para el problema que hemos planteado y se encuentra en utilizar un método contenido en la librería json. ya que eval también ejecutará funciones en JavaScript si el archivo JSON las tiene.php y en el cliente utilizando la librería json./json.responseText. pagina1.js" language="JavaScript"></script> <script src="funciones. .js" language="JavaScript"></script> <script src="funciones. Luego en el navegador emplearemos la librería json.parseJSON()../json.Habíamos visto que para convertir una cadena que contiene información en formato JSON solo debíamos utilizar la función eval de JavaScript. nuestro sitio está en peligro.js addEvent(window. Habíamos resuelto este problema con el siguiente código: var datos=eval("(" + conexion1.'load'.js que verifica que el archivo JSON solo contenga datos.js" language="JavaScript"></script> funciones.js" language="JavaScript"></script> </head> <body> <h2>Recuperar datos del servidor almacenados en una base de datos en formato JSON utilizando la librería JSON. Resolveremos el mismo problema sobre la base de datos de periféricos. Si utilizamos la librería json.responseText + ")"). Esto lo podemos seguir utilizando siempre y cuando la información del archivo JSON provenga de nuestro sitio.

onreadystatechange = procesarEventos. . } var conexion1.funcion).getElementById("resultados").readyState == 4) { alert('Cadena en formato JSON: '+conexion1.nomevento. var datos=conexion1. return true. } else { resultados..php'. } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.attachEvent) { elemento. conexion1. addEvent(ob.captura) { if (elemento.".addEventListener(nomevento.responseText.presionBoton..'click'. function presionBoton(e) { conexion1=crearXMLHttpRequest(). conexion1.length.funcion.open('GET'. conexion1.function inicializarEventos() { var ob=document.parseJSON().f<datos. true).descripcion+"<br>".responseText).attachEvent('on'+nomevento.'pagina1.f++) { salida += 'Codigo:'+datos[f].precio+"<br><br>".innerHTML = salida. } resultados. } else if (elemento. var salida=''.captura).getElementById('boton1').addEventListener) { elemento. salida += 'Precio:'+datos[f]. } function procesarEventos() { var resultados = document.codigo+"<br>".innerHTML = "Cargando. for(f=0.funcion. salida += 'Descripcion:'+datos[f]. return true.false). if(conexion1.send(null).

. echo $cad.mysql_error()). $json=new Services_JSON(). mysql_select_db("bdajax".descripcion. while ($reg=mysql_fetch_array($registros)) { $vec[]=$reg.precio from perifericos". } En la función procesar eventos debemos llamar al método parseJSON: var datos=conexion1.responseText.$conexion) or die("Problemas en el select".} else return false."root".De JSON a PHP (utilizando la librería JSON. return xmlHttp.XMLHttpRequest) xmlHttp = new XMLHttpRequest().parseJSON().XMLHTTP"). else if (window.php. $cad=$json->encode($vec).php')."z80") or die("Problemas en la conexion"). if (window.$conexion) or die("Problemas en la seleccion de la base de datos")./JSON.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. Esto lo podemos hacer ya que la librería añade esta funcionalidad a los string. ?> 24 . . $registros=mysql_query("select codigo. } function crearXMLHttpRequest() { var xmlHttp=null.php no tiene cambios: <?php $conexion=mysql_connect("localhost". el archivo pagina1. } require('.php) Ahora nos queda ver como en el servidor recibir datos con formato JSON y proceder a generar una clase en PHP mediante la librería JSON.

edad:25.$cad->nombre. function inicializarEventos() { var ref=document.false).. addEvent(ref./json..js" language="JavaScript"></script> </head> <body> <h2>Enviar datos desde el navegador en formato JSON y proceder a la decodificación en una clase PHP con la librería JSON.1990] }.toJSONString().. Es decir la clase Services_JSON tiene un método llamado decode que recibe como parámetro una cadena con datos codificados en JSON y procede a retornar la información en un objeto.1700.html <html> <head> <title>Problema</title> <script src=".. sueldos:[1200. Confeccionaremos un problema que envíe desde el navegador información en formato JSON y en el servidor la convertiremos en un objeto de PHP y procederemos a generar un trozo de HTML que retornaremos al navegador para que lo muestre.js" language="JavaScript"></script> <script src="funciones. echo 'Nombre:'. enviarDatos(cadena).php</h2> <input type="button" value="Enviar" id="boton1"> <div id="resultados"></div> </body> </html> El archivo con las funciones JavaScript es: addEvent(window. El archivo pagina1.getElementById('boton1').false).'click'. . var cadena=obj.inicializarEventos..botonPresionado. } . $cad=$json->decode(stripslashes($_REQUEST['cadena'])). } function botonPresionado(e) { var obj={ nombre:'juan'.'load'.La sintaxis es: $json=new Services_JSON(). .

} } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.attachEvent) { elemento. conexion1. true).send(null).funcion.funcion. return true. return xmlHttp. } else { resultados.php?cadena='+cadena.funcion).var conexion1.ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. else if (window.attachEvent('on'+nomevento.. } function procesarEventos() { var resultados = document. } function crearXMLHttpRequest() { var xmlHttp=null.innerHTML = "Cargando.".innerHTML = conexion1.open('GET'.onreadystatechange = procesarEventos. . if(conexion1..'pagina1.captura).responseText.XMLHttpRequest) xmlHttp = new XMLHttpRequest().readyState == 4) { resultados.nomevento. conexion1. if (window. } else if (elemento.captura) { if (elemento.addEventListener) { elemento.addEventListener(nomevento. return true.XMLHTTP"). function enviarDatos(cadena) { conexion1=crearXMLHttpRequest().getElementById("resultados"). conexion1. } else return false.

innerHTML = "Cargando.. echo '<br>'. var cadena=obj. echo '<br>'.$cad->edad. sueldos:[1200. echo 'Nombre:'. conexion1.responseText. echo '<br>'. edad:25. function enviarDatos(cadena) { conexion1=crearXMLHttpRequest(). } else { resultados. La función enviarDatos procede a crear un objeto de la clase XMLHttpRequest y pasa mediante el parámetro GET la cadena en formato JSON: var conexion1.php?cadena='+cadena. echo 'Edad:'. } Solo queda mostrar el trozo de datos en HTML que retorna el servidor: function procesarEventos() { var resultados = document.open('GET'.send(null). luego procedemos a llamar a la función enviarDatos: var obj={ nombre:'juan'.".1700. conexion1. enviarDatos(cadena).toJSONString().innerHTML = conexion1. $json=new Services_JSON().} Cuando se presiona el botón procedemos a partir de un objeto JavaScript generar una cadena en formato JSON. ../JSON.readyState == 4) { resultados.getElementById("resultados").$cad->sueldos[1].$cad->sueldos[0].1990] }.php').php: <?php require('. $cad=$json->decode(stripslashes($_REQUEST['cadena'])).'pagina1.$cad->nombre. true). echo 'Primer sueldo:'. echo 'Segundo sueldo:'. } } Lo nuevo se centra en el archivo pagina1. if(conexion1.onreadystatechange = procesarEventos.. conexion1.

echo '<br>'. Veamos los distintos archivos que intervienen (pagina1. Recordemos que con la función stripslashes sacamos los caracteres de escape(barras invertidad para las comillas entre otras) Luego podemos fácilmente acceder a los atributos del objeto con la sintaxis: echo echo echo echo echo echo echo echo echo 'Nombre:'. 'Tercer sueldo:'.. '<br>'. 25 . '<br>'.js" language="JavaScript"></script> </head> <body style="background:#eee"> <div><strong>Puede desplazar las letras con el mouse para escribir palabras que serán vistas por otros usuarios que visiten la página en este momento o más tarde.html): <html> <head> <title>Problema</title> <script src="./json.$cad->sueldos[2].$cad->sueldos[1]. básicamente desarrollaremos una aplicación que muestre un tablero con letras que se puedan mover con el mouse. ?> El método que convierte una cadena con formato JSON en un objeto de PHP es: $cad=$json->decode(stripslashes($_REQUEST['cadena'])). '<br>'. luego de algunos segundos todos los otros usuarios verán reflejado el cambio en sus navegadores.$cad->sueldos[2]. esto permitirá que cualquier otro usuario que esté ejecutando en ese momento la misma página verá el desplazamiento que efectuó otra persona. Lo interesante será que cada un cierto tiempo nos comunicaremos con el servidor e informaremos las letras que se han desplazado dentro de la ventana.js" language="JavaScript"></script> <script src="funciones.Pizarra interactiva multiusuario El último ejemplo que implementaré y utilizará JSON para la comunicación entre el cliente y el servidor será una "pizarra interactiva multiusuario". 'Segundo sueldo:'. '<br>'.$cad->sueldos[0]. echo 'Tercer sueldo:'.$cad->edad.</strong></div> <div id="letras"></div> .$cad->nombre. 'Edad:'. 'Primer sueldo:'. Podremos observar como se sincronizan las posiciones de las letras dentro de la ventana (si un usuario mueve una letra hacia la derecha. Para probar si realmente funciona esta característica podemos ejecutar el "problema resuelto" utilizando el FireFox y el Internet Explorer.

crearLetras(). function procesarEventos() { if(conexion1. var datosMovil. document./json.setInterval(actualizarCoordenadas.readyState == 4) { datos=conexion1.onreadystatechange = procesarEventos. conexion1. } .</body> </html> Hay que tener en cuenta que emplearemos JSON para la transferencia de datos entre el cliente y el servidor por lo que debemos disponer: <script src=".js" language="JavaScript"></script> Este archivo no tiene nada de especial toda la complejidad se encuentra en el archifo funciones.js" language="JavaScript"></script> Ahora el archivo donde se encuentra toda la complejidad del código que se ejecuta en el cliente está en funciones.php'. var vectorLetras=new Array(). var reloj=null. var pasos=0.onmousemove=desactivarSeleccion. function desactivarSeleccion(e) { return false } var conexion1.open('GET'.false). var datosNuevos. true).responseText.'load'. conexion1=crearXMLHttpRequest().. conexion1. function inicializarEventos() { document. 5000). } var datos.js: addEvent(window.onmousedown=desactivarSeleccion.send(null).js que lo incorporamos con la siguiente línea: <script src="funciones.parseJSON(). relojGeneral=window.'pagina1.inicializarEventos. var relojGeneral=null. conexion1.

y) { this. x. this. ob.datos[f]. for(f=0.retornarY()) { datos[f].random().getElementById('letras').style. var cadena=let.fontSize='18px'. ob.retornarX().style. con++.height='17px'. ob.f<datos. ob.length.x=vectorLetras[f].x.createElement('div').id='div'+f. var ref=document.codigo=cod. ref.background='#eee'.style.f<vectorLetras.position='absolute'.y=vectorLetras[f]. ob. ob.innerHTML=datos[f].retornarX().f+1. vectorLetras[f]=new Recuadro(ob.length. this.y!=vectorLetras[f].x+'px'. var con=0. .datos[f]. } } var aleatorio=Math.datos[f]. ob. ob. ob. ob.x=x.retornarY()).cursor='pointer'.x!=vectorLetras[f].retornarY().codigo.style.y=y. conexion1=crearXMLHttpRequest().style. datos[f]. var x=document.x.y+'px'.style.width='17px'. let[con]=new letrasMovidas(datos[f].vectorLetras[f].style. } function actualizarCoordenadas() { var let=new Array().padding='3px'. } } function letrasMovidas(cod.letra.textAlign='center'.f++) { var ob=document.vectorLetras[f]. ob.toJSONString().} function crearLetras() { for(f=0.style.left=datos[f].retornarX() || datos[f].style.f++) { if (datos[f].style.letra.appendChild(ob).y).top=datos[f].getElementById('div'+f).

x || datosNuevos[f].y-datos[f]. if ((datosNuevos[f].x)>0) avancex=Math.x=parseInt(datosMovil[f]. clearInterval(relojGeneral).php?letras='+cadena+"&aleatorio="+aleatorio. else avancex=Math.round(dx/20). datosMovil[f]. for(f=0.readyState == 4) { datosNuevos=conexion1.conexion1.abs(datosNuevos[f].f<datosNuevos.x!=datos[f]. var dy=Math. 5).'pagina2.send(null).y).x=datos[f].responseText.parseJSON().length.y!=datos[f].parseJSON().open('GET'. conexion1. cambios=true.f++) { if (datosNuevos[f].round(-dx/20).x). } } if (cambios) { if (reloj==null) reloj=window. datosMovil=conexion1. datosMovil[f].y) { cambios=true.x)+avancex. .y=datos[f].length.setInterval(moverLetras. } } } function moverLetras() { var cambios=false.x. for(f=0.x || datosNuevos[f].x-datos[f]. pasos--.y) { datosMovil[f]. conexion1. true).y!=datos[f]. var dx=Math.abs(datosNuevos[f].y.f<datosNuevos.onreadystatechange = procesarEventosContinuos.x!=datos[f]. } function procesarEventosContinuos() { if(conexion1. var cambios=false.responseText.x-datos[f]. pasos=20. var avancey. var avancex.f++) { if (datosNuevos[f].

function coordenadaX(e) { if (window.event) return event.fijarY(datosMovil[f].if ((datosNuevos[f].x). else avancey=Math.clientX+document.y-datos[f]. reloj=null. } else { vectorLetras[f].scrollTop.setInterval(actualizarCoordenadas. vectorLetras[f].false). addEvent(div.'mousedown'.y)+avancey.round(-dy/20).scrollTop. } } } if (pasos==0) { clearInterval(reloj). else return e.event) return event.body.y=parseInt(datosMovil[f].pageY.round(dy/20).y). else return e.inicioDrag.pageX. } } //Drag and Drop Recuadro=function(div) { tX=0.y). relojGeneral=window.x). difX=0.fijarY(datosNuevos[f].fijarX(datosNuevos[f].clientY+document. cambios=true. datosMovil[f]. vectorLetras[f].body.fijarX(datosMovil[f]. } . 5000).y)>0) avancey=Math. tY=0. difY=0. } function coordenadaY(e) { if (window. if (pasos==0) { vectorLetras[f].

false).left).drag. var oX=parseInt(div. div.style.removeEventListener('mouseup'. difY=oY-eY.style. } function soltar(e) { if (window.false).'mousemove'.top).event. addEvent(document.style.removeEventListener('mousemove'. difX=oX-eX.detachEvent('onmouseup'.event) e=window.retornarX=function() { return parseInt(div.left). } this. var oY=parseInt(div.false).soltar). addEvent(document.detachEvent('onmousemove'. } actualizarCoordenadas().false).left=tY.event) e=window. tX=coordenadaY(e)+difY+'px'. document.drag. } . } function drag(e) { if (window.style.top).function inicioDrag(e) { if (window.event) { document.retornarY=function() { return parseInt(div.event. } this. tY=coordenadaX(e)+difX+'px' div. } else { document.style.top=tX. var eY=coordenadaY(e).style. document.'mouseup'. var eX=coordenadaX(e).soltar.drag).soltar.

ActiveXObject) xmlHttp = new ActiveXObject("Microsoft. } } //*************************************** //Funciones comunes a todos los problemas //*************************************** function addEvent(elemento.attachEvent) { elemento.funcion. } function crearXMLHttpRequest() { var xmlHttp=null.nomevento.captura) { if (elemento. esto es para que no se puedan seleccionar las letras.fijarX=function(xx) { div. else if (window.style.fijarY=function(yy) { div.addEventListener(nomevento.this. } else if (elemento.XMLHttpRequest) xmlHttp = new XMLHttpRequest().funcion.onmousemove=desactivarSeleccion.style.captura). } La primera función que se ejecuta es inicializarEventos donde tenemos: document. return true.attachEvent('on'+nomevento.left=xx+'px'.addEventListener) { elemento. Luego: . Con estas dos asignaciones desactivamos la posibilidad de seleccionar texto dentro de la página.onmousedown=desactivarSeleccion.funcion). document. if (window. } this.top=yy+'px'.XMLHTTP"). } else return false. return xmlHttp. return true.

crearLetras().letra.parseJSON(). ob. ob. ob.left=datos[f].getElementById('div'+f).length. ob. conexion1.style.php'. var ref=document.send(null).datos[f]. Veremos más adelante que tenemos una base de datos donde almacenamos las letras y las coordenadas de cada una.cursor='pointer'. La función crearLetras: function crearLetras() { for(f=0.style.'pagina1.background='#eee'.top=datos[f].f+1. relojGeneral=window. vectorLetras[f]=new Recuadro(ob. ob.f<datos.getElementById('letras'). ob.createElement('div'). 5000). ob.style.style.style. ob.letra. La funcion procesarEventos: function procesarEventos() { if(conexion1. } . veremos luego que tiene por objetivo recuperar las coordenadas de las letras almacenadas en el servidor: relojGeneral=window. x.x.datos[f].height='17px'.position='absolute'.datos[f].fontSize='18px'.readyState == 4) { datos=conexion1.f++) { var ob=document.onreadystatechange = procesarEventos.setInterval(actualizarCoordenadas.appendChild(ob).setInterval(actualizarCoordenadas. ref.open('GET'.id='div'+f.width='17px'. ob.style.conexion1=crearXMLHttpRequest().textAlign='center'.style. true).y). Llamamos seguidamente a la función crearLetras() y finalmente creamos un timer o alarma para que se dispare cada 5 segundos. conexion1. 5000). ob.padding='3px'. var x=document. conexion1. ob.style.innerHTML=datos[f]. creamos un objeto de la clase crearXMLHttpRequest para recuperar la posición de cada letra.style. } } cuando los datos se han enviado por completo del servidor procedemos a rescatarlos y generar un objeto literal en JavaScript llamando a la función parseJSON().responseText.y+'px'.x+'px'.style.

y). true).open('GET'.innerHTML=datos[f].x.letra. El ancho y el alto son fijos: ob. ob. Por último lo añadimos a la página: ref.'pagina2. conexion1. ob.top=datos[f].y=vectorLetras[f].length.height='17px'.random().y!=vectorLetras[f].vectorLetras[f] . var cadena=let.toJSONString(). let[con]=new letrasMovidas(datos[f]. for(f=0.datos[f].f++) { if (datos[f].x+'px'. } } var aleatorio=Math.onreadystatechange = procesarEventosContinuos. vectorLetras[f]=new Recuadro(ob.left=datos[f].retornarY().php?letras='+cadena+"&aleatorio="+aleatorio .retornarX().style. datos[f].width='17px'. .retornarX().style. conexion1.x=vectorLetras[f].codigo. y creamos un objeto de la clase Recuadro que nos permitirá desplazarlo con el mouse (esta clase se estudió en el curso de DHTML Ya. Definimos un id distinto a cada uno: ob.f<vectorLetras.datos[f].letra.retornarX() || datos[f].x!=vectorLetras[f]. var con=0.} crea elementos HTML de tipo "div" y los dispone en las coordenadas que acabamos de recuperar del servidor: ob.retornarY()) { datos[f].id='div'+f.datos[f].style. conexion1=crearXMLHttpRequest(). con++.vectorLetras[f].retornarY()).style. La función actualizarCoordenadas se dispara cada 5 segundos o inmediatamente después que un usuario desplaza una letra en la pantalla: function actualizarCoordenadas() { var let=new Array().f+1.y+'px'.

retornarY()). La función procesarEventosContinuos: function procesarEventosContinuos() { if(conexion1. } } if (cambios) . var cambios=false. true).responseText.x!=vectorLetras[f].f<datosNuevos. datosMovil[f]. y además creamos una componente del a clase letrasMoviles: let[con]=new letrasMovidas(datos[f]. } Dentro del for identificamos si alguna de las letras fue desplazada con el mouse: if (datos[f].y=datos[f].y!=datos[f].parseJSON().retornarY()) En caso afirmativo actualizamos la estructura datos: datos[f].parseJSON().x=vectorLetras[f]. datos[f].conexion1.vectorLetras[f] . Recordemos que para convertir el vector de JavaScript a JSON lo hacemos: var cadena=let.toJSONString().x=datos[f].codigo.x || datosNuevos[f].x.open('GET'.'pagina2.readyState == 4) { datosNuevos=conexion1.x!=datos[f].responseText.vectorLetras[f].f++) { if (datosNuevos[f].send(null).y!=vectorLetras[f]. datosMovil=conexion1.retornarX() || datos[f]. Fuera del for creamos un objeto de la clase XMLHttpRequest y procedemos a enviar los datos al servidor: conexion1. Este vector let tiene los cambios efectuados en pantalla para ser eviados al servidor.y.y) { datosMovil[f].retornarX().length.retornarX().y=vectorLetras[f].retornarY(). for(f=0.php?letras='+cadena+"&aleatorio="+aleatorio . cambios=true.

clearInterval(relojGeneral). Utilizamos dos variables ya que una la utilizaremos para ir desplazando lentamente la letra por la pantalla. pasos=20. if ((datosNuevos[f].round(dx/20). var dx=Math.parseJSON(). La función moverLetra: function moverLetras() { var cambios=false.parseJSON().x)>0) avancex=Math.length.x!=datos[f]. 5).x-datos[f].y) { En caso de haber diferencias: if (cambios) { if (reloj==null) reloj=window. 5). pasos--.abs(datosNuevos[f].responseText. for(f=0.setInterval(moverLetras.x || datosNuevos[f].x).y!=datos[f]. clearInterval(relojGeneral). Dentro de un for verificamos si hay coordenadas distintas entre las que administra nuestro navegador y las registradas en el servidor: if (datosNuevos[f].x-datos[f]. .responseText. datosMovil=conexion1.y) { cambios=true.{ if (reloj==null) reloj=window.x!=datos[f].f<datosNuevos. pasos=20. } desactivamos el timer relojGeneral y activamos un timer para desplazar lentamente las letras entre la posición actual y la registrada en el servidor (la función moverLetras se dispara cada 5 milisegundos.setInterval(moverLetras. } } } Recupera las coordenadas actuales de las letras que se encuentran registradas en el servidor: datosNuevos=conexion1.y!=datos[f]. var avancex.f++) { if (datosNuevos[f].x || datosNuevos[f].

abs(datosNuevos[f].$conexion) or die("Problemas en la seleccion de la base de datos").y. } } } if (pasos==0) { clearInterval(reloj)."root". Luego tenemos los dos archivos que se ejecutan en el servidor (pagina1. vectorLetras[f].y=parseInt(datosMovil[f]. if ((datosNuevos[f].x)+avancex.y).else avancex=Math.php): <?php $conexion=mysql_connect("localhost".$conexion) or die("Problemas en el select".fijarY(datosMovil[f]..y).codigo from letras".fijarX(datosNuevos[f]. cambios=true. reloj=null. $registros=mysql_query("select letra. while ($reg=mysql_fetch_array($registros)) { $vec[]=$reg.round(-dx/20).y)>0) avancey=Math. vectorLetras[f]. Esta función se ejecuta 20 veces hasta que la variable global pasos almacene el valor 0. datosMovil[f]./JSON. if (pasos==0) { vectorLetras[f].y).round(-dy/20).fijarX(datosMovil[f]. } } desplaza las letras que han cambiado de posición. } mysql_close($conexion). else avancey=Math. require('.x=parseInt(datosMovil[f].y)+avancey. mysql_select_db("bdajax".x.mysql_error()).php')."z80") or die("Problemas en la conexion"). var avancey.x).y-datos[f].round(dy/20).y-datos[f].setInterval(actualizarCoordenadas. var dy=Math. 5000). relojGeneral=window. datosMovil[f]. . } else { vectorLetras[f].fijarY(datosNuevos[f].x).

$conexion) or die("Problemas en la seleccion de la base de datos"). $registros=mysql_query("select letra. echo $cad.mysql_error()). Por último nos queda el archivo que llamamos cada 5 segundos para indicarle las novedades dentro del navegador (si el usuario desplazó alguna letra) y recuperar las novedades registradas en el servidor: <?php require('." where codigo=". $json=new Services_JSON().mysql_error()).x.php'). for($f=0..".php').mysql_error()).$cad[$f]->y. echo $cad.$cad[$f]->x.mysql_error()).codigo from letras".$json=new Services_JSON(). $cad=$json->decode(stripSlashes($_REQUEST['letras'])).y.y=".$conexion) or die("Problemas en el select".$conexion) or die("Problemas en el select". ?> Recupera de la tabla letras las coordenadas y letras propiamente dichas que serán mostradas en el servidor: $registros=mysql_query("select letra. Guardamos los datos en un vector: while ($reg=mysql_fetch_array($registros)) { $vec[]=$reg. } $registros=mysql_query("select x.y. } mysql_close($conexion). $cad=$json->encode($vec). $cad=$json->encode($vec). } Generamos un archivo con formato JSON para que se envíe al cliente: require('.x.. mysql_select_db("bdajax".codigo from letras"./JSON.y./JSON.$f<count($cad).$cad[$f]->codigo."z80") or die("Problemas en la conexion"). while ($reg=mysql_fetch_array($registros)) { $vec[]=$reg. $json=new Services_JSON(). .codigo from letras". $conexion=mysql_connect("localhost"."root".$conexion) or die("Problemas en el select".$conexion) or die("Problemas en el select".$f++) { mysql_query("update letras set x=".

$json=new Services_JSON(). Modificamos las coordenadas de las letras: $registros=mysql_query("select letra.$cad[$f]->x.$f<count($cad). $cad=$json->encode($vec). . echo $cad." where codigo=". $json=new Services_JSON(). for($f=0.mysql_error()).$conexion) or die("Problemas en el select". ?> Primero recuperamos los datos enviados por el navegador y generamos un vector asociativo en PHP a partir de los datos que llegan en formato JSON: $cad=$json->decode(stripSlashes($_REQUEST['letras'])).mysql_error()).$conexion) or die("Problemas en el select".codigo from letras".$conexion) or die("Problemas en el select".".codigo from letras".y.mysql_error()).$f++) { mysql_query("update letras set x=".y. $cad=$json->encode($vec). } mysql_close($conexion). while ($reg=mysql_fetch_array($registros)) { $vec[]=$reg.$cad[$f]->y. echo $cad. } Por último recuperamos todas las letras y sus coordenadas y las enviamos nuevamente al cliente (navegador) que las solicitó: $registros=mysql_query("select x.y=".$cad[$f]->codigo.x.