En aplicaciones en las que necesitamos enviar datos al servidor, ya sea mediante un formulario o una petición AJAX con estructura diferente, tenemos algunas limitaciones si seguimos el modelo tradicional:
Ben Alman lo explicaba de forma muy simple con un ejemplo de formulario HTML típico:
<form action="dump.php" method="get"> <input type="checkbox" name="a" value="1" checked="checked"> <input type="checkbox" name="a" value="2" checked="checked"> <input type="checkbox" name="a" value="3" checked="checked"> <input type="submit" name="Submit" value="submit"> </form> |
Si envíamos este formulario, los datos que el servidor devuelve a la página dump.php tendrían la siguiente estructura URL:
?a=1&a=2&a=3 |
A la hora de manejar estos datos con un lenguaje como PHP, el resultado puede que no sea el esperado:
<?PHP var_dump( $_GET ); ?> |
Esto nos da:
array(1) { ["a"]=> string(1) "3" } |
En lugar de crear un array con tres elementos, a[ «1», «2», «3» ] , el intérprete PHP va asignando cada uno de los valores que encuentra de forma secuencial hasta detenerse en el último.
Para evitar este problema, la idea es conseguir enviar una estructura de tipo array en la URL para que PHP la interprete correctamente:
?a[]=1&a[]=2&a[]=3 |
Esto daría el resultado esperado en nuestra script PHP:
array(1) { ["a"]=> array(3) { [0]=> string(1) "1" [1]=> string(1) "2" [2]=> string(1) "3" } } |
Para conseguir este comportamiento, los desarrolladores web llevan tiempo añadiendo la notación del array [] a los nombres de aquellas propiedades que tienen que funcionar como tales. En el caso de nuestro formulario anterior, el código quedaría de la siguiente forma:
<form action="dump.php" method="get"> <input type="checkbox" name="a[]" value="1" checked="checked"> <input type="checkbox" name="a[]" value="2" checked="checked"> <input type="checkbox" name="a[]" value="3" checked="checked"> <input type="submit" name="Submit" value="submit"> </form> |
Mediante esta técnica, conseguimos enviar estructuras de datos anidadas con el nivel de complejidad que necesitemos. Por ejemplo, serían válidas construcciones del tipo:
&a[]=1 &a[][x]=1 &a[2][x][1]=1 ... |
Dependiendo de cuántos niveles compogan la estructura, el marcado en el formulario se va complicando de forma progresiva facilitando que aparezcan bugs difíciles de detectar. Además de esto, si hablamos de peticiones AJAX que no toman los datos de un formulario sino de arquitecturas de datos completamente diferentes, la cosa se vuelve inmanejable.
Utilizando jQuery
Hasta la versión 1.4 de jQuery, el problema de enviar estructuras anidadas de datos era similar a lo descrito anteriormente.
Tomemos como ejemplo la siguiente petición AJAX:
$.get( 'test.php', { a : [ 1, 2, 3 ] }, function( data ){ /* ... */ } ); |
En este caso, similar al que vimos al principio, nos daría como resultado que PHP asignaría a la variable ‘a’ el valor ‘3’. No nos vale.
Para solucionar esto, tendríamos que incluir la notación literal del array a nuestra propiedad ‘a’:
$.get( 'test.php', { "a[]" : [ 1, 2, 3 ] }, function( data ){ /* ... */ } ); |
Hay que tener cuidado de encerrar la cadena ‘a[]‘ entre comillas para que no resulte en un error de sintaxis. Como podemos comprobar, aunque PHP procese esta estructura de forma correcta, resulta como mínimo incómoda.
Llendo un poco más allá, si probáramos con algo más complejo como un objeto, veríamos como PHP directamente lo ignora:
$.get( 'test.php', { "a[]" : [ 1, 2, 3 ], b : { foo : 'Hello', bar : 'World' } }, function( data ){ /* ... */ } ); |
Añadir manualmente en este caso la notación para que nuestro objeto se convierta en un array sería complejo y daría como resultado una cadena inmanejable con un riesgo potencial de errores.
En estos casos es cuando jQuery.param puede ayudarnos preparando la query correcta por nosotros.
jQuery.param
La función jQuery.param permite crear una representación serializada de un array o un objeto preparada para utilizarse como URL query o en una petición AJAX.
La sintaxis es la siguiente:
jQuery.param( obj, [ traditional ] ) |
Donde:
– obj: es el array o el objeto que se quiere serializar.
– traditional: es un valor booleano que indica aplica el método tradicional en lugar del optimizado desde la versión 1.4.
Siguiendo los ejemplos anteriores, para conseguir enviar nuestro array, ahora tendríamos:
var myArr = { a : [1,2,3] }; console.log( $.param( myArr ) ); // a%5B%5D=1&a%5B%5D=2&a%5B%5D=3 |
Como podemos ver, incluso se escapan los caracteres. Si aplicamos decodeURIComponent, obtenemos una cadena más legible:
console.log( decodeURIComponent( $.param( myArr ) ) ); // a[]=1&a[]=2&a[]=3 |
Gracias a este método, podemos ahora construir estructuras complejas y tan anidadas como necesitemos:
var crazyParams = $.param( { a : [ 0, [ 1, 2 ], [ 3, [ 4, 5 ], [ 6 ] ] ], b : [ 7, [ 8, 9 ] ] } ); console.log( decodeURIComponent( crazyParams ) ); // a[]=0&a[1][]=1&a[1][]=2&a[2][]=3&a[2][1][]=4&a[2][1][]=5&a[2][2][]=6&b[]=7&b[1][]=8&b[1][]=9 |
Conclusión
Con jQuery.param, podemos serializar estructuras de datos complejas y anidadas con la confianza de que serán codificadas en una única cadena fácil de descomponer por un lenguaje de tipo servidor como PHP o Ruby. Sin embargo, no hay que llevar esta funcionalidad a extremos irracionales: para esas estructuras con multitud de elementos, siempre es recomendable utilizar formatos más adecuados como JSON que cuenta con todo el soporte nativo de los navegadores actuales. Dependerá de cada situación el escoger el método más apropiado para manejar y compartir datos entre las diferentes partes de una aplicación.
Excelente articulo, me gustó por que va desde la raíz del problema hasta formular la solución, con esa metodología puedes continuar aportando mucho a la sociedad web mundial. Felicitaciones…!