Contenido

Combos dependientes accesibles con PHP y jQuery

27 may

+ 15

En el último proyecto en el que estoy desarrollando en el trabajo he tenido que crear unos combos dependientes, hasta el momento siempre los había hecho con Javascript, usando Ajax para cargar los datos de un combo a otro, pero para este proyecto quería hacerlo un poco más accesible.

Como ya hemos visto en muchos posts, el desarrollar pensando en ser accesibles para todo el mundo es complicado, pero no imposible.

Empecemos

Lo primero que tenemos que hacer es tener claro que es lo que queremos hacer, en el ejemplo, una select de destino que dependerá de una select padre llamada pais.

combos_dependientes_accesibles

Viendo que es lo que necesitamos crear, veamos como podría ser una aproximación al código PHP que necesitamos.

Al código…

Primero vayamos por partes, y como hay que empezar por alguna definamos la estructura en el servidor y ya iremos subiendo.

destino.php

<?php if ($_POST["type"] == "xml")	header ("content-type: text/xml"); ?>
<select id="destino" name="destino">
        <option value="-1">Selecciona una zona</option>
<?php if ($_POST["pais"] == "ES"){ ?>
	<option value="PMI">Palma de Mallorca</option>
	<option value="AGP">Malaga</option>
	<option value="BCN">Barcelona</option>
<?php } else if($_POST["pais"] == "FR") { ?>
	<option value="TOU">Toulousse</option>
	<option value="CHD">Charles de Gaulle</option>
<?php } ?>	
</select>

Este fichero es un ejemplo rápido de un XML bien formado, que a su vez hará de elemento <select /> en nuestro script. La primera línea nos condicionará, más adelante, el formato de salida que usaremos. Ahora veamos en donde lo incrustamos.

index.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es_ES">
<head>
	<title>Combos dependientes accesibles</title>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
	<form id="form" method="post" action="<?=$url?>">
		<p class="pais">
		Pais: 
			<select name="pais" id="pais">
				<option value="-1">Selecciona un pais</code>
				<option value="ES">España</code>
				<option value="FR">Francia</code>	
			</select>
		</p>
		<p class="destino">
			<?php echo "Destino: ";
			      include("destino.php"); 
 			?>
		</p>
		<p class="submit">
			<input type="submit" value="Enviar" />
		</p>
	</form>
</body>
</html>

Como vemos, lo incluimos mediante un include normal, que nos generará el HTML necesario para que veamos un <select />.

Si ahora miramos el código resultante, nos encontramos con esto.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es_ES">
<head>
	<title>Combos dependientes accesibles</title>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
	<form id="form" method="post" action="<?=$url?>">
		<p class="pais">
		Pais: 
			<select name="pais" id="pais">
				<option value="-1">Selecciona un pais</code>
				<option value="ES">España</code>
				<option value="FR">Francia</code>	
			</select>
		</p>
		<p class="destino">
			Destino:
			<select id="destino" name="destino">
				<option value="-1">Selecciona una zona</option>
			</select>
		</p>
		<p class="submit">
			<input type="submit" value="Enviar" />
		</p>
	</form>
</body>
</html>

Como podemos ver, se trata de un HTML normal, sin ningún tipo de secreto. Ahora empezemos a ponerle polvos mágicos para que esata rana se convierta en principe.

Abracadabra…

Para hacer mágia, voy a usar jQuery (principalmente por su simplicidad para el ejemplo) y con él veremos lo fácil que es conseguir unos combos disponibles para todos. Primero hemos de volver a replantearnos los ficheros PHP

<?php	
	$hayPais = false; // No hay pais por defecto
	if (isset($_POST["pais"])) $hayPais = true; //Si hay país
	
	// URL de destino
	$url =  ($hayPais)?"receptor.php":"";	
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es_ES">
<head>
	<title>Combos dependientes accesibles</title>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
	<form id="form" method="post" action="<?=$url?>">
		<p class="pais">
		Pais: 
			<?php if ($hayPais) : ?>
				<input type="text" name="pais" value="<?=$_POST["pais"]?>" />
			<?php else: ?>
		<select name="pais" id="pais">
			<option value="-1">Selecciona un pais</code>
			<option value="ES">España</code>
			<option value="FR">Francia</code>	
		</select>
		<?php endif;?>
		</p>
		<p class="destino">
			<?php if ($hayPais) {
				echo "Destino: ";
				include("destino.php"); 
			} else { ?>
				<noscript>
					<input type="submit" value="Buscar Destinos" />
				</noscript>
			<?php }	?>
		</p>
		<p class="submit">
			<input type="submit" value="Enviar" />
		</p>
	</form>
</body>
</html>

Vayamos por partes:

<?php	
	$hayPais = false; // No hay pais por defecto
	if (isset($_POST["pais"])) $hayPais = true; //Si hay país
        /*
		Esta versión es más corta, pero menos ilustrativa.
		$hayPais = isset($_POST["pais"]); // ¿Existe $_POST["pais"];
	*/
	
	// URL de destino
	$url =  ($hayPais)?"receptor.php":"";	
?>

Con la variable $hayPais, arrastramos por todo el script un valor Booleano que nos permite conocer si el parámetro $_POST["pais"] existe. De esta forma, las futuras comprobaciones son más sencillas.

Acto seguido, nos encargamos de informar la variable $url, que contendrá la URL a donde ha de ser redirigido el formulario. Esto es simplemente para conseguir submitar al lugar correcto en cada paso.

<?php if ($hayPais) : ?>
	<input type="text" name="pais" value="<?=$_POST["pais"]?>" />
<?php else: ?>
	<select name="pais" id="pais">
		<option value="-1">Selecciona un pais</code>
		<option value="ES">España</code>
		<option value="FR">Francia</code>	
	</select>
<?php endif;?>

Al igual que la comprobación anterior, sabiendo que hemos recibido el parámetro $_POST["pais"], modificamos el <select /> por un elemento <input /> con el valor que hemos pasado previamente. Esto nos servirá para submitar el valor a la página siguiente.

<?php if ($hayPais) {
	echo "Destino: ";
	include("destino.php"); 
} else { ?>
        <noscript>
	<input type="submit" value="Buscar Destinos" />
	</noscript>
<?php }	?>

Aqui es donde está parte de la gracia del script, y curiosamente se llama <noscript />. Como podemos ver, en caso de haber pasado el parámetro $_POST["pais"], cargaremos el fichero destino.php y este ya se encargará de mostrar los datos relacionados al parámetro enviado. En caso de no enviar este parámetro, insertaremos el tag <noscript /> que contendrá un elemento <input type="submit" /> que se encargará de submitar el formulario con el valor necesario para cargar $_POST["pais"].

Hasta ahora, todo bien. Salvo para los que si tenemos Javascript activo. No nos olvidemos que el tag <noscript /> no será mostrado en caso de disponer de Javascript en nuestro navegador. Para ello, debemos extendernos a la siguiente capa, la del javascript.

Mejorando la experiencia del usuario

Como hemos dicho antes, usaremos jQuery para la capa de cliente. Así, que manos a la obra.

<?php	
	$hayPais = false; // No hay pais por defecto
	if (isset($_POST["pais"])) $hayPais = true; //Si hay país
	
	// URL de destino
	$url =  ($hayPais)?"receptor.php":"";	
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es_ES">
<head>
	<title>Combos dependientes accesibles</title>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
	<script type="text/javascript" src="jquery.js"></script>
	<script type="text/javascript">
		$(document).ready(function(){
			// Creamos elemento destino y lo incrustamos en <p class="destino">
			$("p.destino").append('Destino: <select id="destino" name="destino"><option value="-1">Seleciona un destino</option></select>');

			// Modificamos el action del formulario a la página receptora.
			$("form#form").attr("action", "receptor.php");

			// Definimos la petición de ajax, al fichero destino.php
			$("#pais").bind("change", function() {
			    $.post("destino.php", {pais: $(this).val(), type: "xml"}, function(xml){
			        $("#destino").empty();
			        $(xml).find("option").each(function(x,el) {
			         $("#destino").append('<option value="'+$(el).attr("value")+'">' +$(el).text() + '</option>');
			        });
			    }, "xml");
			});

		});
	</script>
</head>
<body>
	<form id="form" method="post" action="<?=$url?>">
		<p class="pais">
		Pais: 
			<?php if ($hayPais) : ?>
				<input type="text" name="pais" value="<?=$_POST["pais"]?>" />
			<?php else: ?>
		<select name="pais" id="pais">
			<option value="-1">Selecciona un pais</code>
			<option value="ES">España</code>
			<option value="FR">Francia</code>	
		</select>
		<?php endif;?>
		</p>
		<p class="destino">
			<?php if ($hayPais) {
				echo "Destino: ";
				include("destino.php"); 
			} else { ?>
				<noscript>
					<input type="submit" value="Buscar Destinos" />
				</noscript>
			<?php }	?>
		</p>
		<p class="submit">
			<input type="submit" value="Enviar" />
		</p>
	</form>
</body>
</html>

Destripémoslo un poco para entenderlo mejor.

<script type="text/javascript" src="jquery.js"></script>

Cargamos jQuery para disponer de las ventajas que nos ofrece este framework.

// Creamos elemento destino y lo incrustamos en <p class="destino">
$("p.destino").append('Destino: <select id="destino" name="destino"><option value="-1">Seleciona un destino</option></select>');

Dentro del $(document).ready(... definimos las tareas que ayudarán al usuario. La que vemos arriba se encarga de añadir el <select /> de destinos vacio en el lugar apropiado, pendiente de ser relleneado con la petición ajax.

// Modificamos el action del formulario a la página receptora.
$("form#form").attr("action", "receptor.php");

Modificamos el action del formulario para que la ruta de submit sea la correcta.

// Definimos la petición de ajax, al fichero destino.php
$("#pais").bind("change", function() {
    $.post("destino.php", {pais: $(this).val(), type: "xml"}, function(xml){
      $("#destino").empty();
      $(xml).find("option").each(function(x,el) {
         $("#destino").append('<option value="'+$(el).attr("value")+'">' +$(el).text() + '</option>');
       });
    }, "xml");
});

Con este código, lanzamos una petición a nuestro fichero destino.php con los parámetros pais y type, cargamos con los datos que necesitamos para que al detectar un cambio en el elemento <select id="pais" /> este envie la petición indicando que quiero recibir los datos en XML para luego recorrerlo y pintar las option que necesito para rellenar <select id="destino" />

Resultado

El resultado es una página en la que podemos acceder con dos posibles configuraciones, con Javascript o sin él. En caso de entrar con javascript, todo estará preparado para usarlo y hacer que selección de destino sea mediante Ajax y en un solo paso.

En caso de tener el javascript desactivado, tendremos que realizar un paso más para cargar los datos referentes al destino, pero al final enviaremos los mismo datos a la página siguiente.

Podeis probarlo en esta demo que he montado, solo he podido probar el JS en Firefox, así que si alguien me lo puede probar en otros navegadores se lo agradeceré.

Espero vuestras opiniones, y sugerencias.

Web Development Helper monitoriza ajax en tu Internet Explorer

25 may

+ 4

Gracias a edusanver descubro Web Development Helper es un plugin para Internet Explorer que nos permite, entre otras cosas, monitorizar las peticiones Ajax como si de Firebug en Firefox se tratara.

web_development_helper

Características

Entre las características más interesantes de este plugin se encuetran:

  • Inspector DOM de todos los elementos.
  • Capturas de imagenes de la página en la que estás.
  • Log de las peticiones HTTP (o HTTPS) solicitadas por el navegador o peticiones Ajax.
  • Ver las peticiones y respuestas en detalle.
  • Habilidad de filtrar por tipos de URL’s en los logs.
  • Traza de errores en detalle de las peticiones Javascript.
  • Consola con posibilidad de interacción Javascript usando (window.debugService).

Requerimientos

Descargar

Descargar

Nuevo Google Reader para el iPhone/iPod Touch

13 may

+ 7

Hace unos meses hablabamos de los cambios en Google Reader para adaptarlo a las posibilidades del iPhone/iPod Touch.

reader4iphone.jpg

Estás mejoras ayudaban a los usuario de estos dispositivos a ver claramente los artículos sindicados sin tener que ampliar o reducir el contenido para poder leerlo.

Ahora la gente de Google Reader estrena un nuevo rediseño enfocado más aún a facilitar esta tarea, mediante el uso de Ajax, consigue mitigar las recargas de páginas y se centra únicamente en el contenido.

mobilescroll-small

Podemos ver una demos, pulsando aqui.

30 scripts javascript/Ajax excepcionales

12 may

+ 2

Interesante recopilación de scripts desarrollados en Javascript con los que podremos aportar más funcionalidades a nuestras aplicaciones web. Desde el fantástico Growl de Daniel Mota, hasta el Sliding Date Picker, pasando por jQuery virtual tour, glassBox o MooWheel forman parte de esta fantástica colección.

Using.js, el javascript onDemand llevado al máximo

14 abr

+ 2

Via Ajaxian, descubro Using.js, un script que nos permite usar javascript ondemand sin ningún tipo de complicaciones. Para los que no sepan que es el Javascript on Demand, es aquel javascript que cargamos cuando lo necesitamos y no al principio de la ejecución de la página.

De esta forma, ya hemos visto alguna vez que podemos optimizar el javascript que enviamos a cada usuario, dependiendo de lo que el usuario necesite. Con using, hacer esto es todavía más fácil.

Declaramos los scripts a usar

Lo primero que hemos de hacer, es declarar en el header las posibles librerías que vayamos a usar, para ello usaremos el método register() al que le informaremos un identificador que lo relacionará con la URL del script.

using.register("jquery", "/scripts/jquery-1.2.3.js");

Usando los scripts declarados

Para usar el script definido, deberemos indicar el identificador que queremos usar, y en ese momento cargará el script desde la URL que informamos con anterioridad.

using("jquery"); // loads jQuery and de-registers jQuery from using
$("a").css("text-decoration", "none");

Usandolo los scripts asincronamiente

Otra opción interesante es la de usar los script de forma asincrona, para ello tendremos que indicarlo en la declaración del script.

using.register("jquery", true, "http://cachefile.net/scripts/jquery-1.2.3.js");
using("jquery", function() {
$("a").css("text-decoration", "none"); //async callback
});

Descargar / Demo

41 de los mejores plugins de MooTools

10 abr

+ 1

Una selección de las mejores aplicaciones desarrolladas con MooTools. Como era de esperar, Window.Growl está en la lista, y ahora que está disponible con la versión 1.2 de MooTools con más razón.

Avalancha de Frameworks ¿Con cual nos quedamos?

10 abr

+ 16

Cuando trabajamos con Javascript nos encontramos que por culpa de las diferencias entre los diferentes navegadores, tenemos que condicionar nuestro código dependiendo de estas diferencias. Para ello, y por la comodidad y claridad que aportan al código, los frameworks javascript llegan, y en masa, para hacer felices y fáciles las horas que dedicamos a este lenguaje.

Personalmente siempre que puedo, los evito. Por lo menos para hacerlo yo, aunque sea solo una vez, pero la comodidad de uso y la seguridad de que va a funcionar en la mayoría de casos, engancha.

Por eso, si estamos pensando en usar uno de ellos para nuestras aplicaciones, debemos conocer las posibles alternativas de las que podemos hacer uso.

1. Prototype (http://www.prototypejs.org/)

Pese a ser la más usada, es la que menos conozco de las más conocidas. Famosa por su peso y la integración con script.aculo.us. Muchisima documentación.

Ejemplo

//Nuevo elemento
var a = new Element('a', { 'class': 'foo', href: '/foo.html' }).update("Next page");
//Ajax
new Ajax.Request('/some_url',
{
method:'get',
onSuccess: function(transport){
var response = transport.responseText || "no response text";
alert("Success! \n\n" + response);
},
onFailure: function(){ alert('Something went wrong...') }
});

Documentación / Descargar

2. MooTools (http://mootools.net/)

El primer framework que me enamoró, sin duda llegué atraido por la vistosidad de Moo.fx. Destinada principalmente para complementar el diseño de las aplicaciones web, con una gran cantidad de efectos. Todo ello sin descuidar las funcionalidades del día a día. Importante tener en cuenta la nueva versión 1.2 que será completamente diferente.

Ejemplos

// Crear un elemento
new Element('a', {
'styles': {
'display': 'block',
'border': '1px solid black'
},
'events': {
'click': function(){
//aaa
},
'mousedown': function(){
//aaa
}
},
'class': 'myClassSuperClass',
'href': 'http://mad4milk.net'
});
//Ajax
var myAjax = new Ajax(url, {method: 'get});
myAjax.request();

Documentación / Descargar

3. jQuery (http://jquery.com/)

Mi nuevo amor, hace cosa de un mes, que en los ratos libres voy migrando heySilver a jQuery. Intentando aprender los grandes y mejorando el código semana a semana. Sin lugar a dudas he descubierto que pese a no disponer de muchos efectos ni transiciones, dispone de todo lo necesario para hacer lo más fácil posible el trabajo diario.  La posibilidad de usar xPath y Selectores CSS para encontrar elementos de nuestro HTML es simplemente una maravilla.

// Nuevo elemento
$("#elemento span").append('<p class="clase"><a href="...">Enlace</a></p>');
// Ajax
$.ajax({
type: "POST",
url: "some.php",
data: "name=John&location=Boston",
success: function(msg){
alert( "Data Saved: " + msg );
}
});

Documentación / Descargar

4. MochiKit (http://www.mochikit.com/)

Nunca he tenido la oportunidad de meterle mano, quizas ha sido por falta de tiempo, quizas por falta de interes o quizas la poca claridad del código, pero si revisamos la documentación nos damos cuenta de que no es un framework que podamos desechar sin por lo menos dedicarle un par de semanas.

//Nuevo elemento
P({"class" : "clase"});
//Ajax
var url = "/src/b/bo/bob/MochiKit.Async/META.json";
var d = loadJSONDoc(url);
var gotMetadata = function (meta) {
if (MochiKit.Async.VERSION == meta.version) {
alert("You have the newest MochiKit.Async!");
} else {
alert("MochiKit.Async "
+ meta.version
+ " is available, upgrade!");
}
};
var metadataFetchFailed = function (err) {
alert("The metadata for MochiKit.Async could not be fetched :(");
};
d.addCallbacks(gotMetadata, metadataFetchFailed);

Documentación / Descargar

5. Script.aculo.us (http://script.aculo.us/)

Aunque técnicamente es un complemento de prototype, ya que sin él no funciona, es posiblemente más famoso que el propio Prototype. Con él todos los efectos, transiciones y transformaciones son mas fáciles desde que script. aculo.us apareció.

//Nuevo elemento
element = Builder.node('p',{className:'error'},'An error has occurred');
// Ajax
new Ajax.Request('/foo/bar', {method:'post', postBody:escape('thisvar=true&thatvar=Howdy')});

6. Rialto (http://rialto.improve-technologies.com/wiki/)

Otra gran desconocida de este mundillo de líneas de código, pese a no estar compuesta de una gran cantidad de funcionalidades diarias, está cargado de widgets de fácil instalación que merece la pena ver.


//Nuevo Elemento (Combo)
var comb = new rialto.widget.Combo([["value1","text1"],["value2","text2"],["value3","text3"]],"MyComb",5,10,100,CADRE2,{position:"absolute",heightItem:25,suggest:false,enable:true});
//Ajax
var remote=new rialto.io.AjaxRequest({
url:'rialtoModel.xml',
method: 'get',
callBackObjectOnSuccess:this,
withWaitWindow:false,
onSuccess: this.parseXmlForListValue
}) ;

Documentación / Descargar

7. Dojo (http://dojotoolkit.org/)

Documentación / Descargar

8. Spry Framework (http://labs.adobe.com/technologies/spry/)

Documentación / Descargar

9. ASP.NET Ajax Framework (http://asp.net/ajax/)

Documentación / Descargar

10. Clean Ajax (http://sourceforge.net/projects/clean-ajax/)

Documentación / Descargar

11. YUI (http://developer.yahoo.com/yui/)

Documentación / Descargar

12. Ext (http://extjs.com/)

Documentación / Descargar

13. Base2 (http://code.google.com/p/base2/)

Documentación / Descargar

14. DOMAssistant (http://domassistant.com/)

Documentación / Descargar

Muchos, pero muchos más.

XDomainRequest() y como Microsoft hace lo que le da la gana

9 mar

+ 2

Uno de los problemas con los que nos encontramos al usar Ajax en nuestras aplicaciones es que nos es imposible acceder, mediante javascript, a contenidos de otro servidor usando el el objeto XMLHTTPRequest(), debiendo recurrir a alternativas algo “sucias”, por ello la W3C decidió dotar a este objeto la posibilidad de trabajar en cross-domain, osea entre diferentes dominios. Esto facilitaría, por ejemplo la lectura de feeds, o cualquier tipo de contenido servido por páginas externas a nuestro dominio.

La aparición del primer borrador por parte de la W3C, hizo que los principales navegadores centraran su atención en esta nueva funcionalidad y se pusieran manos a la obra para dotar a sus navegadores de tan esperada y necesaria funcionalidad.

Con la aparición de un navegador que dije que no volvería a nombrar proximamente, apareció otra vez el dilema. XDomainRequest() ha sido el desencadenante, al alejarse del estandar ofrecido por la W3C.

Según la página del propio Microsoft, el uso de este nuevo objeto sería así:

// 1. Creamos el objeto XDR
xdr = new XDomainRequest();

// 2. Abrimos la conexión con el servidor usando el método POST
xdr.open("POST", "http://www.contoso.com/xdr.txt");

// 3. Enviamos información al servidor
xdr.send("data to be processed");

Como podemos ver, esto se parece a la actual forma de usar el objeto XMLHttpRequest() con la diferencia del nombre del objeto y de que la url a la que solicitamos la información se trata de una URL absoluta en lugar de una relativa.

Algo similar a lo propuesto por la W3C, que era extender al objeto XMLHttpRequest() con la capacidad de acceder a servidores remotos sin necesidad de modificar el código existente.

var xhr = new XMLHttpRequest();
xhr.open("GET", "https://www.anieto2k.com/.../datos.php", true);
xhr.onreadystatechange = function(){
  if ( xhr.readyState == 4 ) {
    if ( xhr.status == 200 ) {
      document.body.innerHTML = "Respuesta: " + xhr.responseText;
    } else {
      document.body.innerHTML = "ERROR";
    }
  }
};
xhr.send(null);


Como podemos ver la diferencia nos hace recordar el odiado ActiveX() y las condiciones tan feas que hemos de hacer para hacer compatibles nuestros navegadores. ¿Ahora con la nueva versión tendremos que añadir una línea más?

var ajax =  function() {
  if (windows.XDomainRequest) { //IE8
	return new XDomainRequest();
  } else if (window.XMLHttpRequest) { //FF, Opera, IE7
    	return new XMLHttpRequest();
  } else if (window.ActiveXObject) { //IE6
  	return new ActiveXObject('Microsoft.XMLHTTP')
  } else { //No Ajax Compatibles
    	alert("No hay ajax");
   	return null;
  }
}

¿Nos encontramos con un nuevo ActiveX() (versión exclusiva para Internet Explorer 6.0) o será el nuevo innerHTML (Aceptado como parte del estandar tras ser una invención de Microsoft)?

DOMAssistant, otro framework para trabajar con Javascript

3 mar

+ 1

Si has probado algunos frameworks en Javascript y no te acaban de convencer, echalé un vistazo a DOMAssistant, cubrirá todas tus necesidades sin ocupar espacio con efectos visuales que nunca usarás. [Documentación][Descargar]

Colección de CheatSheets sobre Ajax

3 feb

+ 4

Si desarrollas con alguno de los frameworks de Javascript, y usas frecuentemente los módulos de Ajax disponibles en cada uno de ellos, no necesitarás disponer de estas hojas a mano para no olvidarte de nada mientras los usas.