Diferència entre revisions de la pàgina «NF1 - AJAX»

De wikiserver
Dreceres ràpides: navegació, cerca
(Exercicis curs 2021-2022)
(Solucions)
Línia 632: Línia 632:
 
http://wikiserver.infomerce.es/index.php/NF1_-_AJAX#Exercicis
 
http://wikiserver.infomerce.es/index.php/NF1_-_AJAX#Exercicis
  
== Solucions ==
+
 
  
  

Revisió del 10:11, 7 abr 2022

AJAX

Ajax significa Asynchronous JavaScript i XML, un terme que va ser encunyat per Jesse James Garrett en Adaptive Path, el febrer de 2005. S'hi descriu una metodologia de desenvolupament d'aplicacions web d'una manera diferent a la tradicional. Segons l'article, les aplicacions web i llocs tradicionals funcionen sincrònicament-cada vegada segueix un enllaç, o quan s'envia un formulari, el navegador envia les dades al servidor, el servidor (amb sort) respon, i tota la pàgina s'actualitza. Aplicacions Ajax funcionen de forma asíncrona, el que significa que envies dades d'anada i tornada entre el navegador i el servidor sense haver de recarregar tota la pàgina. Substitueix només les parts de la pàgina que canvia.

Ajax vs traditional.png


El realment bo d'això és que la comunicació entre el motor Ajax i el navegador passa a través de JavaScript i no a través de carregar la pàgina. En termes pràctics, això significa per a l'usuari final menys temps d'espera per carregar les pàgines i la visualització, i més fàcil la interacció amb la pàgina, per que pots sol·licitar dades i continuar llegint el text o el contingut d'una altre part de la pàgina.

Els principals elements d'AJAX

Ajax no és una tecnologia única. Més aviat, és una col·lecció de quatre tecnologies que es complementen:

Tecnologia Expliació
JavaScript És un llenguatge de scripting de propòsit general dissenyat per a ser integrat dins les aplicacions. L'intèrpret de JavaScript en un navegador web permet la interacció programàtica amb moltes de les capacitats incorporades del navegador. Aplicacions Ajax estan escrits en JavaScript.
Cascading Style Sheets (CSS) Ofereix una forma de definir els estils visuals reutilitzables per a elements de la pàgina web. Ofereix una forma senzilla i potent de definir i aplicar un estil visual consistent. En una aplicació Ajax, l'estil d'una interfície d'usuari es pot ajustar de forma interactiva a través de CSS.
Document Object Model (DOM) El DOM presenta l'estructura de les pàgines web com un conjunt d'objectes programables que poden ser manipulats amb JavaScript. Scripts del DOM permet a una aplicació Ajax modificar la interfície d'usuari sobre la marxa, tornar a dibuixar de manera efectiva les parts de la pàgina.
XMLHttpRequest object (XHR) El objecte XMLHttpRequest permet que els programadors web recuperarin les dades des del servidor web com una activitat de fons. El format de dades és típicament XML, però funciona bé amb totes les dades basades en text.

Funcionament

L'objecte XHR ens permet fer peticions HTTP al servidor i rebre la resposta mitjançant programació , en lloc que el navegador doni automàticament la resposta com una nova pàgina . El primer que hem de fer és crear un objecte XHR. A continuació , proporcionar-li la informació que necessita per realitzar la sol·licitud i finalment , gestionar la resposta quan ens la donen.Entre l'enviament de la sol·licitudi la recepció de la resposta , hi ha feina per fer en el servidor, i algunes linies més de codi que hem d'escriure en PHP, Java, .NET o qualsevol altre.

Ens interessa principalment el codi del costat del client, a més la mecànica del costat del servidor de maneig d'una senzilla petició Ajax no són molt diferents de programació web pre-Ajax.

Lifecycle-ajax.png

El API XMLHttpRequest

El cor d'AJAX és una API anomenada XMLHttpRequest(XHR), disponible en els llenguatges de scripting en el costat del client,com ara JavaScript. S'utilitza per realitzar peticions, HTTP o HTTPS, directament al servidor web, i per carregar les respostes directament a la pàgina del client. Les dades que rebem des del servidor es poden rebre en forma de text pla o text XML. Aquestes dades podran ser utilitzats per modificar el DOM del document actual, sense haver de recarregar la pàgina, o també podran ser avaluats amb JavaScript, si són rebuts en format JSON. XMLHttpRequest juga un paper molt important en la tècnica AJAX, ja que sense aquest objecte, no seria possible realitzar les peticions asíncrones al servidor. Una de les limitacions de XMLHTTPR equest és que, per seguretat, només ens deixa realitzar peticions AJAX, a les pàgines que es trobin allotjades en el mateix domini, des del qual s'està realitzant la petició AJAX.


L'objecte XHR (XMLHttpRequest)

En un món perfecte, el codi escrit per a un navegador funcionaria en tots els navegadors. Ja hem après que no vivim en aquest món, i les coses no són diferents quan es tracta d'Ajax. Hi ha una manera estàndard de fer peticions asíncrones a través de l'objecte JavaScript XHR, i una manera patentada Internet Explorer que utilitza un control ActiveX. Amb IE 7, un embolcall que emula la interfície estàndard està disponible, però IE 6 requereix codi diferent. Un cop creat l'objecte XHR, el codi per configurar, iniciar i respondre a la sol·licitud és relativament independent del navegador, i la creació d'una instància de XHR és fàcil per a qualsevol navegador en particular. El problema és que els diferents navegadors implementen XHR de diferents maneres, i hem de crear la instància de la manera adequada per al navegador actual. Utilitzarem la técnica featured detection per averiguar quin objecte XHR podem crear pel navegador actual. Exemple de la creació d'aquest Objecte:

var xhr;
if (window.ActiveXObject) { //Iexplorer
	xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
else if (window.XMLHttpRequest) { //Tots els altres navegadors que soporten ajax
	xhr = new XMLHttpRequest();
}
else {
	throw new Error("Ajax is not supported by this browser");
}

Mètodes i propietats de l'objecte XHR

Primer donem una ullada als mètodes del Objecte XMLHttpRequest:

Mètode Descripció
abort() Fa que la Sol·licitud que s'està executant sigui cancel·lada.
getAllResponseHeaders() Retorna una cadena que conté els noms i valors de totes les capçaleres de resposta.
getResponseHeader(name) Retorna el valor de la capçalera de la resposta anomenada 'named'.
open(method,url,async, username,password) Estableix el mètode HTTP (GET o POST) i l'URL de destinació de la sol·licitud. Opcionalment, la sol·licitud pot ser declarada síncrona (async=false), i es pot subministrar un nom d'usuari i contrasenya per a les sol·licituds que requereixen autenticació.
send(dades) dades: S'usa en el cas que estiguem utilitzant el mètode POST, com a mètode d'enviament.Si fem servir GET, dades serà null
setRequestHeader(name,value) Afegeix el parell etiqueta / valor a la capçalera de dades que s'enviarà al servidor

Exemples amb els diferents mètodes de enviament d'informació (GET i POST):

  • Exemple amb GET: Amb el mètode GET els paràmetres es passen a la mateixa URL.
xmlhttp.open("GET", "datos.php?curso=SMX1&tutor=Julio+Noguera", true);
xmlhttp.send(null);
  • Exemple amb POST: Con el método POST los parámetros se pasan con la función datos.send().
xmlhttp.open("POST","datos.php",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("curso=SMX1&tutor=Julio+Noguera"); 

si no s'estableix la capçalera "Content-Type" correcta, el servidor descarta totes les dades enviades mitjançant el mètode POST. D'aquesta manera, al programa que s'executa en el servidor no li arriba cap paràmetre. Així, per enviar paràmetres mitjançant el mètode POST, és obligatori incloure la capçalera "Content-Type"

Propietats del Objecte XMLHttpRequest:

L'objecte XMLHttpRequest, disposa de les següents propietats, que ens faciliten informació sobre el estat de la petició al servidor, i on rebrem les dades de la resposta retornada a la petició AJAX:

Propietat Descripció
onreadystatechange Emmagatzema una funció (o el nom d'una funció), que serà cridada automàticament, cada vegada que es produeixi un canvi en la propietat readyState.
readyState Emmagatzema l'estat de la petició XMLHTTPRequest. Possibles estats, del 0 al 4:

0: sol·licitud no inicialitzada.

1: connexió establerta amb el servidor.

2: sol·licitud rebuda.

3: processant sol·licitud.

4: sol·licitud ja acabada i la resposta està disponible.

responseText Conté les dades de resposta, com una cadena de text.
responseXML Si es responseText és XML aqui trobem l'arbre XML DOM associat. Datos devueltos por el servidor en forma de documento XML que puede ser recorrido mediante las funciones del DOM (getEementsByTagName, etc.).Retorna un [object XMLDocument]
status El codi d'estat de resposta retornat pel servidor. Per exemple: 200 per a l'èxit o el 404 perquè no es troba. Consulteu l'especificació HTTP per a tot el conjunt de codis.
statusText El missatge de text de l'estat retornat pel servidor. (per exemple: "Not Found" o "OK").

Utilització de l'objecte XHR

Ara que tenim una instància XHR creada, donem una ullada al que es necessita per configurar i executar la sol·licitud al servidor.

  • Especificar un mètode HTTP com GET o POST
  • Especificar la URL del servidor al que demanarem la informació a mostrar a l'usuari
  • Especificar a l'objecte XHR la manera que volem saber del progrès de la petició
  • Especificar la informació a enviar al servidor (content).

Amb la següent sentencia javascript especifiquem els primers dos items del llistat anterior:

xhr.open('GET', 'url');
o
xhr.open('POST', 'url');

Tingues en compte que la sentencia anterior no envia res al servidor, només estem configurant l'objecte per tal que utilitzi un servidor i un mètode de conexió HTTP.

El tercer item diu que hem de dotar a l'objecte XHR amb un mecanisme d'avís per fer-nos saber com va la petició ajax. Per fer-ho, s'ha d'assignar una funció de resposta (callback function) a la propietat onreadystatechange del objecte XHR. Aquesta funció l'executarà l'objecte XHR en diverses ocasions, segons l'estat amb el que es trobi l'objecte.

xhr.onreadystatechange = function() {
	if (this.readyState == 4) {
		if (this.status >= 200 && this.status < 300) { 
			// només ens interesa si la petició al servidor 
			// s'ha completat i ha estat correcta.
		}
		else {
			// problema amb la petició
		}
	}
}

A l'últim item s'ha d'especificar, si hi ha, la informació necessaria que necessita saber el servidor per tal de processar correctament la petició. Finalment, enviar la petició. Aixó s'aconsegueix amb el mètode send() de l'objecte XHR.

xhr.send("a=1&b=2");

Resposta del servidor mitjançant l'objecte XHR

Una vegada s'ha completat la petició al servidor podem agafar la seva resposta (response) del objecte XHR. El format de la resposta pot ser qualsevol format en mode TEXT; no està limitat a XML. De fet, la majoria del temps, la resposta de Ajax és un altre format. Aquest pot ser text planer, un fragment HTML o pot ser una representació d'objecte de JavaScript com és JSON.

Sigui quin sigui el format del text, la resposta es pot obtenir mitjançant la propietat responseText del objecte XHR. Si la resposta està en format XML, per que s'ha especificat utilitzant el tipus MIME text/xml o application/xml, es tractada i es crea un arbre DOM que està disponible a la propietat responseXML del objecte XHR.

Una vegada tenim la resposta del servidor la hem de carregar al element DOM apropiat.

Exemple:

xhr.onreadystatechange = function() {
	if (this.readyState == 4) {
		if (this.status >= 200 && this.status < 300) {
			document.getElementById('someContainer').innerHTML = this.responseText;
		}
	}
}


var objetoXHR = new XMLHttpRequest();

       function obtenerDatosServidor(origen, elemento)     //Función “obtenerDatosServidor” contiene dos parámetros
       {
           var objeto_destino = document.getElementById(elemento); // Se elige el elemento HTML a ser modificado.
           objetoXHR.open(“GET”, origen);                 //Se configura una conexión asíncrona con una URL.
           objetoXHR.onreadystatechange = respuesta;    // Se indica la función a ser llamada una vez el estado
                                                          // del objeto cambie. 
           objetoXHR.send(null);                          // Se abre la conexión.
       }
     
       function respuesta()
       {
            if (objetoXHR.readyState == 4 && objetoXHR.status == 200) 
            {
            objeto_destino.innerHTML = objetoXHR.responseText;
            }
       }


EJEMPLO GET EN AJAX

SERVIDOR GET

<?php
$seleccion = $_GET['curso'];
$tutor = $_GET['tutor'];

echo "curso ".$seleccion." tutor ".$tutor ;


GET con AJAX

  <script>
        window.onload = function () {
            let datos;

            function mostrar_datos() {
                if (datos.readyState == 4 && datos.status == 200)
                    document.getElementById("resultado").innerHTML = datos.responseText;

            }

            function iniciar() {
                var url = 'get.php';
                var params = formulario.curso.name + '=' + formulario.curso.value + '&' + formulario.tutor.name + '=' + formulario.tutor.value;
                datos = new XMLHttpRequest();
                datos.open("GET", url + '?' + params, true);
                datos.onreadystatechange = mostrar_datos;
                datos.send(null);
            }

            document.getElementById("boton").onclick = iniciar;
        }
    </script>

</head>

<body>

    <form name="formulario" method="get" action="get.php">
        <label>Curso: </label>
        <select name="curso">
            <option value="SMX1" selected> SMX1 </option>
            <option value="SMX2"> SMX2 </option>
        </select>
        <label>Tutor: </label>
        <input type="text" name="tutor" />
        <input type="button" id="boton" name="boton" value="ok">

    </form>
    <br>
    <h3>CONTENIDO:</h3>
    <div id="resultado">resultado</div>
</body>

VIDEOTUTORIAL

https://youtu.be/b7GuKxIQYOg

EJEMPLO POST EN AJAX

SERVIDOR POST

$seleccion = $_POST['curso'];
$tutor = $_POST['tutor'];
echo "curso ".$seleccion." tutor ".$tutor;

POST con AJAX

<script type="text/javascript">
        var datos;

        function pedir_datos(url, params) {
            datos = new XMLHttpRequest();
            datos.open("POST", url, true);
            datos.onreadystatechange = mostrar_datos;
            datos.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            //Llamamos al método setRequestHeader indicando que los datos a enviarse están codificados como un formulario.
            datos.send(params);
        }

        function mostrar_datos() {
            if (datos.readyState == 4 && datos.status == 200)
                document.getElementById('resultado').innerHTML = datos.responseText;
        }

        function iniciar() {
            var url = 'post.php';
            var params = formulario.curso.name + '=' + formulario.curso.value + '&' + formulario.tutor.name + '=' + formulario.tutor.value;
            pedir_datos(url, params);
        }
    </script>

</head>

<body>
    <form name="formulario" method="post" action="javascript: iniciar()">
        <label>Curso: </label>
        <select name="curso">
            <option value="SMX1"> SMX1 </option>
            <option value="SMX2" selected> SMX2 </option>
        </select>
        <label>Tutor: </label>
        <input type="text" name="tutor" value="Julio Noguera" />
        <input type="submit" name="submit" value="boton" />
    </form>
    <div id="resultado"> </div>
</body>

CORS

Esta cabecera la ponemos para que peticiones AJAX se acepten desde fuera del dominio. Sin ella, no funcionaria las peticiones al hosting XXXXX.

Esta cabecera NO debe estar si haceis peticiones AJAX entre un mismo dominio

header("Access-Control-Allow-Origin: *");

VIDEOTUTORIAL

https://youtu.be/ULSCT3nYzJ8

FETCH

API fetch es que utiliza promesas, es decir, devuelve un objeto con dos métodos, uno then() y otro catch() a la que pasaremos una función que será invocada cuando se obtenga la respuesta o se produzca un error.

Aquí hay que aclarar un punto con los errores: si se devuelve un código HTTP correspondiente a un error no se ejecutará el catch(), ya que se ha obtenido una respuesta válida, por lo que se ejecutará el then(). Sólo si hay un error de red o de otro tipo se ejecutará el catch().

Otro aspecto importante que hay que comprender es que para obtener el body o cuerpo del mensaje devuelto por el servidor deberemos obtener una segunda promesa por medio de los métodos del objeto Response. Por ello será muy habitual ver dos promesas encadenadas, una para el fetch() y otra con el retorno del método que utilicemos para obtener el body.

fetch('https://httpbin.org/ip')
    .then(function(response) { //Este objeto 'response' contiene la respuesta que hace el servidor y dispone de una serie de propiedades con los valores de esa respuesta
        console.log('response.body =', response.body);
        console.log('response.bodyUsed =', response.bodyUsed);
        console.log('response.headers =', response.headers);
        console.log('response.ok =', response.ok);
        console.log('response.status =', response.status);
        console.log('response.statusText =', response.statusText);
        console.log('response.type =', response.type);
        console.log('response.url =', response.url);
        return response.text();
    })
    .then(function(data) {
        console.log('data = ', data);
    })
    .catch(function(err) {
        console.error(err);
    });

-hemos llamado a fetch() con la URL a la que queremos acceder como parámetro esta llamada nos devuelve una promesa

-el método then() de esa promesa nos entrega un objeto response

-del objeto response llamamos al método text() para obtener el cuerpo retornado en forma de texto

-nos devuelve otra promesa que se resolverá cuando se haya obtenido el contenido

-el método then() de esa promesa recibe el cuerpo devuelto por el servidor en formato de texto

-hemos incluido un catch() por si se produce algún error


let data = new FormData();   
// También se puede enviar cambiando el FormData
// data = new URLSearchParams("profesor=Julio&INS=La Merce");
data.append('profesor', 'Julio');
data.append('INS', 'La Mercè');
fetch('./datos.php', {
   method: 'POST',
   body: data
})
.then(function(response) {
   if(response.ok) {
       return response.text()
   } else {
       throw "Error en la llamada Ajax";
   }

})
.then(function(texto) {
   console.log(texto);
})
.catch(function(err) {
   console.log(err);
});

SERVIDOR

echo $_POST["INS"].$_POST["profesor"];

OTRA FORMA RECUPERANDO DATOS DEL FORMULARIO

HTML

<form  action='./datos.php' id="formulario" method="POST">
  Input1: <input name='input1'><br>
  Input2: <input name='input2'><br>
  <input type='submit'>
</form>
</body>

JS

var testForm = document.getElementById('formulario');
    testForm.onsubmit = function(event) {   //en el momento que se activa un botón submit
    event.preventDefault();   //evita que se propague el evento recargando la página.
    var formData = new FormData(document.getElementById('formulario'));  //recupera los datos del formulario.
   
fetch('./datos.php', {
   method: 'POST',
   body: formData
})
.then(function(response) {
      if(response.ok) {
       return response.text()
   } else {
       throw "Error en la llamada Ajax";
   }

})
.then(function(texto) {
   console.log(texto);
})
.catch(function(err) {
   console.log(err);
});

  }


SERVIDOR

echo $_POST["input1"].$_POST["input2"];

VIDEOTUTORIAL

Promeses: https://www.youtube.com/watch?v=pHBmmbDQl0o

FETCH: https://youtu.be/6BeO1gObVS8



https://www.todojs.com/api-fetch-el-nuevo-estandar-que-permite-hacer-llamadas-http/

https://cursos.mejorcodigo.net/article/el-fetch-api-en-javascript-43

https://desarrolloweb.com/articulos/fetch-post-ajax-javascript.html

AXIOS

Axios es una librería JavaScript que puede ejecutarse en el navegador y que nos permite hacer sencillas las operaciones como cliente HTTP, por lo que podremos configurar y realizar solicitudes a un servidor y recibiremos respuestas fáciles de procesa.

Así que Axios es una alternativa que nos brinda multitud de ventajas:

  • La API es unificada para las solicitudes Ajax.
  • Está optimizado para facilitar el consumo de servicios web, API REST y que devuelvan datos JSON.
  • De fácil utilización y como complemento perfecto para las páginas convencionales.
  • Pesa poco, apenas 13KB minimizado. Menos aún si se envía comprimido al servidor.
  • Compatibilidad con todos los navegadores en sus versiones actuales.

TABLA COMPARATIVA

https://www.javascriptstuff.com/ajax-libraries/

GET

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
 axios({
    url: 'https://api.github.com/users/julio', //Endpoint
    method: 'GET',  //Método
    timeout: 3000,  //Tiempo máximo de espera
    responseType: 'JSON',  //Tipo de respuesta (Por defecto es JSON)
    }).then(function (response) {
       //Si todo OK te imprime la respuesta
       console.log(response.data); //Datos de la respuesta
       console.log(response.status); //Estatus
       console.log(response.statusText); //Mensaje del estatus
       console.log(response.headers); // Encabezados
    }).catch(function (error) {
       //Si hay error el catch lo imprime
       console.log(error.response); //Objeto respuesta
       console.log(error.response.data); // Respuesta del servidor
       console.log(error.response.status); //Código de error
       console.log(error.response.statusText); //Mensaje del error
   });
 </script>

POST

let data = new FormData();
        data.append('nombre', 'John');
        data.append('apellido', 'Die');
        axios({
                url: 'data.php',
                method: 'POST',
                data: data
            }).then(function (response) {
                console.log(response.data);
            }).catch(function (error) {
                console.log(error.response.statusText);
            });

FORMA MÁS ABREVIADA GET

axios.get('/user?ID=12345')
      .then(function (response) {
        console.log(response);
      })
      .catch(function (error) {
        console.log(error);
      });


FORMA MÁS ABREVIADA POST

let data = new FormData();
        data.append('nombre', 'John');
        data.append('apellido', 'Die');
        axios.post('data.php', data)
              .then(function (response) {
                console.log(response);
            }).catch(function (error) {
                console.log(error);
            });

VIDEOTUTORIAL

https://youtu.be/-Fl11UJmYSQ

https://www.hoclabs.com/2017/05/30/axios-promesas-y-http/

ASYNC AWAIT

https://codingpotions.com/vue-axios#async--await-para-las-llamadas

https://blog.nexlab.dev/tech/2018/08/31/que-es-async-await-en-javascript.html

https://www.oscarblancarteblog.com/2019/03/15/javascript-async-await/

https://www.youtube.com/watch?v=stiPdlSkTOI

Exercicis

Exercici 1

Crea una petició amb AJAX per tal de conèixer els paràmetres de configuració del php. Et recordo que per obtenir-los només cal executar la funció de php anomenada phpinfo();

Exercici 2

Realitzar un exercici que mostri per pantalla en quin estat de petició està (1 al 4) per pantalla, per a això s'haurà d'afegir en un fitxer anomenat espera a php o jsp amb una pausa de tres segons i quan acabi haurà de mostrar el temps abans i després d'aquest temps.

Exercici 3

Crea dos camps (nom i cognom). Envia la informació mitjançant AJAX al servidor PHP i fes que et retorni els valors passats a majúscules. Insereix directament amb HTML la informació a un DIV a la pàgina

Exercici 4

Desplegables encadenats. Es vol crear 2 desplegables en HTML que la seva informació la obtingui del servidor mitjançant AJAX. El primer Desplegable ha de contenir les següents ciutats: Barcelona, Madrid, Sevilla, LaCoruña. El segon desplegable mostrarà els Barris de la Ciutat escollida al primer desplegable.

Exercici 5

  • a)Crea un formulari que demani nom d'usuari i contrasenya. Crea un botó de validació que validi amb AJAX que l'usuari introduït no existeixi. Si existeix s'ha de proposar un nom alternatiu. Com no utilitzarem BD crea un fitxer on a cada linia hi hagi un nom d'usuari. El nou nom d'usuari no ha de coincidir amb cap dels noms que apareix a la llista.
  • b)Crea un Botó anomenat enviar que mitjançant AJAX envii el nom d'usuari i la contrasenya al servidor. El nom d'usuari s'ha d'afegir al fitxer anterior.

Exercici 6

Es tracta de crear un input que s'introduiran noms i mitjançant ajax consultar la base de dades si hi ha el nom en cas d'existir ha de mostrar tots els noms que comencen amb les lletres introduïdes

ocult

Exercicis curs 2021-2022

  • Exercicis 4 i 6 amb objecte XMLHttpRequest
  • Exercicis 4 i 6 amb fetch
  • Exercicis 4 i 6 amb axios

Solucions

http://wikiserver.infomerce.es/index.php/NF1_-_AJAX#Exercicis



https://www.svnlabs.com/blogs/php-spotify-web-api/

https://developer.spotify.com/dashboard/

Referències

Bibliografia

Bear Bibeault, Yehuda Katz, "JQuery in Action Second Edition", Ed. Manning, 2010, ISBN 978-935182-32-0

Dace Crane, Bear Bibeault, Jord Sonneveld,"Ajax in Practice", Ed. Manning, 2007, ISBN 1-932394-99-0

Christian Heilmann, "Beginning JavaScript with DOM Scripting and Ajax", Ed. Apress, 2006, ISBN 1-59059-680-3