Wednesday 27 May 2009

Cargar javascript desde JSON o AJAX con eval() en FF y execScript() en IE

¿Estás desarrollando una aplicación web en la que usas JSON o AJAX para cargar dinámicamente datos? ¿Además necesitas cargar dinámicamente no solamente datos sino también código javascript para ser utilizado en la página? A continuación te expongo el modo de hacerlo para que funcione en FireFox 3.X y IE7 (casualmente, también funciona en IE6).

Voy a partir de la base de que utilizas jQuery para la consulta JSON o AJAX al servidor. Y me voy a centrar en la "carga" del código javascript. Pero obviamente, no importa la librería o código que uses para el JSON o AJAX. Hay muchísima literatura en internet sobre ese tema.

Ejemplo de carga de datos

Empezaré con un ejemplo de carga de datos tipo texto, que es lo más habitual. Y luego pondré un ejemplo de carga de código javascript.


function js_actualizar_top_webs(){
var url_json = 'json_top_webs.php?mes='+$('#select_mes').val();
$.getJSON(
url_json,
function(datos){
$('#div_top_webs').html(datos.table_webs);
}
);
}

Imaginemos que en nuestra web de ejemplo tenemos un control tipo lista desplegable (select) que permite al usuario escoger un mes del año, y queremos que nuestra página recargue un <div id="'div_top_webs'"></div> con la lista del top 10 de webs de ese mes. Es un ejemplo clásico de recarga de datos dinámica usando JSON o AJAX.

Para ello construimos una función llamada js_actualizar_top_webs, que llamaremos al cambiar el valor de ese select. Esta función tal como está definida en el código de ejemplo hace una llamada JSON mediante el objeto $ de jQuery y cuando los datos se hayan recibido por completo ejecutará el código en rojo, en dónde "datos" es un objeto de javascript (no un array!!) que contiene diferentes "propiedades" con los datos enviados. En este caso, suponemos que el archivo de PHP que ha sido llamado devuelve un string llamado "table_webs" que contiene el código HTML de un "<table>" con la lista de webs que queremos mostrar.

Para "obtener" el valor de ese string HTML simplemente llamamos a datos.table_webs y lo colocamos como "contenido" de "div_top_webs" mediante el método .html() de jQuery. ¿Sencillo, no?


Ejemplo de carga de código javascript


Bueno, vamos ahora a algo que "cuesta" un poquitín más. Bueno, de hecho a mí me ha hecho gastar casi 8 horas de cansada búsqueda por internet y de leer mucho y probar mucho, hasta llegar a lo que te voy a poner aquí! ;)

Abajo tienes el código anterior ligeramente cambiado: hemos añadido unas líneas de código más, con el fin de poder cargar y ejecutar un código de javascript elaborado en el lado servidor.



function js_actualizar_top_webs(){
var url_json = 'json_top_webs.php?mes='+$('#select_mes').val();
$.getJSON(
url_json,
function(datos){
$('#div_top_webs').html(datos.table_webs);
if (window.execScript) window.execScript(datos.script_leyenda);
else window.eval(datos.script_leyenda);
}
);
}

Puedes ver en rojo dos nuevas líneas que corresponden a una sentencia condicional, y esto es necesario para ejecutar un código u otro según estemos en FireFox o en Internet Explorer (como mínimo estos dos navegadores). Para ambos casos el código de javascript pasado es el mismo y lo recuperamos de nuevo mediante jQuery con la propiedad datos.script_leyenda (que habremos rellenado desde el PHP con el código javascript que necesitemos ejecutar en nuestra web).

La diferencia radica en que Internet Explorer ejecutará el código de javascript mediante el método window.execScript(), mientras que FireFox ejecutará el código al usar el método window.eval(), en ambos casos pasando como argumento el código javascript que queremos ejecutar.

Otro aspecto importante y que tal vez pase desapercibido a primera vista es que en ambos casos ejecutamos sendos métodos sobre el objeto window. Eso es fundamental (me llevó más de una hora leyendo descubrirlo), para que el código javascript a ejecutar pase a estar "disponible" desde otros "ámbitos" de la misma página. De esta forma, si por ejemplo, dentro de ese código cargado dinámicamente definimos una función llamada "js_mostrar_leyenda()", si queremos usarla en el resto de la página, deberemos llamarla así: window.js_mostrar_leyenda();

Estoy seguro de que a más de uno le va a ir de perlas estas 3 líneas de código! al menos a mí me va a dar mucha potencia de programación con JSON y javascript. Y sinceramente, cuesta encontrar información "actualizada" en internet. Ya sabes que este tipo de información técnica (especialmente cross-browser) se desfasa con facilidad, con la salida de nuevas versiones de navegadores continuamente!! Así que lo que es válido hoy deja de serlo al cabo de 2 años :(

Te invito a que comentes cualquier sugerencia que tengas al respecto, eh! seguro que a todos nos interesa (temas de compatibilidad, por ejemplo). Si probando el código ves que te funciona en otros navegadores, por favor, coméntalo brevemente ;)


Actualización 2012-mar-06

Bajo petición de un comentarista añado a continuación un ejemplo de cómo debería ser el código PHP del archivo

json_top_webs.php 

que uso en los ejemplos de arriba.

1  <?php
2 
3       $ret
=array(
4                 
'table_webs'=>'<p>table</p>',
5                 
'script_leyenda'=>"alert('Hi world');"
6                 
);
7                
8       echo 
json_encode($ret);
9 
10  
?>

No necesita mucha explicación, pero por los que empiezan con el PHP:
  • definimos un array con dos elementos que llevan el nombre que luego usaremos en el javascript (como "datos.table_webs").
  • fijaros en el valor de cada uno de ellos. El primero es código HTML tal cuál, y el segundo es CUALQUIER instrucción o instrucciones de javascript, desde un simple alert() hasta definir funciones si es necesario.
  • por último hacemos un echo del array pasándolo primero por la función nativa de PHP json_encode() que lo que hace es reescribir los datos en formato JSON (ya sabéis: con llaves, comillas dobles, y comas, escapando los valores que haga falta). Cuidado porqué esta función creo que no estaba en algunas versiones de PHP 4.x ! pero en fin, quiero pensar que hace años que todo el mundo actualizó ya a PHP 5.x

Un saludo!!!
SERGI

8 comments:

  1. hola me interesa este tema de json y queria preguntar si es posible que realices otros ejemplos de json usando jquery ya que uso jquery casi para muchas cosas y deseo comenzar a usarlo con json, php, mysql. Serviria de mucho un ejemplo para mostrar mas de un dato desde la base de datos
    Atte.
    Luis Osorio
    osorio.luis05@gmail.com

    ReplyDelete
  2. hola Luis, ya me gustaría tener más TIEMPO para poner mśa ejemplos! :))) en serio que me encanta producir material educativo... pero sinceramente, voy a tope!

    En internet puedes encontrar -por poco que busques- muchos ejemplos, creo que como el que pides, incluso en habla hispana!

    A este respecto te recomiendo este blog que tiene muy buenos artículos con excelentes ejemplos, como por ejemplo este que también habla de la intergración de JSON con PHP:

    http://blog.unijimpe.net/json-con-php

    Además, me he tomado la licencia de poner público para ti (y espero que le sirva a alguien más) mi última mini-aplicación web: un cronómetro de tiempo para controlar el tiempo dedicado a una lista de proyectos. Usa javascript, JSON y PHP. No usa MySQL, pues guarda y recupera la información en archivos de texto plano ;) Pero creo que te dará muchas ideas de cómo trabajar con JSON y PHP ;)

    Me gustaría algún día dedicarle a este proyecto (que he llamado "timer") un poco de tiempo para poder publicarlo como opensource. Pero en fin... de momento lo encuentro funcional pero faltan acabar unos pocos detalles para que pueda considerarse RC. De momento está en beta :)))

    Un saludo!
    Me alegra saber que de vez en cuando me lee alguien ;)

    ReplyDelete
  3. Me dejé poner el enlace a TIMER:

    http://www.imasdeweb.com/documentos/BLOG/timer.zip

    ReplyDelete
  4. Gracias Usher web voy a ver la url que mandastes y tambn el zip de timer que se escucha excelente para el manejo del tiempo ya que siempre suele ser complicado aunque se use DB.
    SALUDOS

    ReplyDelete
  5. bueno muchas gracias por tu tiempo para con nosotros te lo agradecemos todos lo q leemos y denuevo gracias..

    ReplyDelete
  6. Oye mi estimado, sera que puedas poner un ejemplo de como se rellena script? soy muyyy nuevo en esto sorry

    ReplyDelete
  7. perdon script_leyenda

    ReplyDelete
  8. Hola Anonymous, añadí al artículo original un ejemplo de lo que creo que me pides. Si no era eso avísame. Espero que te sea útil.

    Un saludo!
    SERGI

    PD: firmen poniendo su nombre como mínimo en el comentario... es muy feo ir haciendo favores o hablando con "anónimos" ;)

    ReplyDelete