Mostrando entradas con la etiqueta codigo. Mostrar todas las entradas
Mostrando entradas con la etiqueta codigo. Mostrar todas las entradas
Cargar scripts JavaScript una sola vez + llamar función cuando la carga termina
Programando interfaces con JavaScript me topé con un problema al que no encontré una solución concreta. Cuando tenemos una página dinámica que carga scripts JS usando AJAX a medida que los va necesitando, podemos caer en el problema de cargar el mismo script más de una vez. Esto se debe a que de antemano no sabemos si el script se cargó o no y lo necesitamos para cumplir alguna función. Un ejemplo rápido de ver es el caso de asignar un evento a un componente. Supongamos que tenemos una página con el siguiente componente: <DIV ID="contenedor">contenido</DIV> y tenemos una sección que cambia según el accionar del usuario, pero carga un script jQuery de la siguiente forma:
$.getScript('/js/bind.js');
cuyo contenido es el siguiente:
$('#contenedor').click(function(event){ $("#contenedor").append("hola"); });
Si llamamos la misma sección más de una vez, lo que sucederá es que el evento click se enlaza más de una vez al componente "contenedor", haciendo que la palabra "hola" se agregue varias veces, en lugar de una sola vez como se esperaría. Van entendiendo por dónde va el problema? De alguna forma, la sección que carga el script debería saber que el script ya se cargó y no debería cargarlo de nuevo. El tema es cómo saber esto... En internet encontré algunas alternativas (sobre todo en StackOverflow) que explican cómo escapar este problema, pero al parecer ni JavaScript, ni jQuery implementan una solución directa, el programador debe encargarse de diseñar una función a tal fin. Otro problema con el que me topé relacionado a esto es cómo saber en qué momento se terminaron de cargar varios scripts. Si usas jQuery, ellos recomiendan usar la función $(document).ready() para esperar a que la página se cargue. La realidad es que cuando se cargan scripts con $.getScript, el evento ready no espera a que estos scripts se carguen. No obstante $.getScript permite definir una función como parámetro que será llamada cuando el script se termine de cargar... pero y si queremos esperar a que un conjunto de scripts se carguen? Para matar dos pájaros de un tiro (los problemas citados), diseñé una función jQuery denominada load_script, la cual decidí compartir con el mundo porque ninguna de las soluciones que encontré me pareció completa. Esta función está basada en distintas propuestas de distintos usuarios de StackOverflow. La función utiliza dos variables globales: loaded_scripts y loading_scripts. loaded_scripts mantiene la lista de scripts que ya se cargaron, así no se los vuelve a cargar nuevamente, mientras que loading_scripts mantiene la lista de scripts que se están cargando actualmente, para saber en qué momento se terminó de cargar todo. Los parámetros de la función son: script_list y callback. script_list es un arreglo con la lista de scripts que se deben cargar y por los cuales debe esperarse a que carguen, mientras que callback es una función definida por el programador que se llamará cuando todos los scripts se terminen de cargar.
/**
 * Load the given JavaScript scripts and call the callback function when all of them are fully loaded.
 * Each script is loaded only once, meanning that if this function is called two times with the same script name
 * it will be loaded the first time. This avoids problems like redeclared functions or variables, event binded more than
 * once, and every other error produced by a script loaded multiple times.
 * The function uses two global array variables:
 *  loaded_scripts: scripts that has been already loaded. Used to know which scripts should not be loaded again.
 *  loaded_scripts: scripts that are in loading process. Used to know when the loading process is done.
 * 
 * @param script_list array containing the scripts links to load. Ex: ['/js/load_this.js', '/js/binder.js']
 * @param callback the function to call when loading of the scripts is done.
 */
var loaded_scripts = Array();
var loading_scripts = Array();
jQuery.fn.load_scripts = function(script_list, callback)
{
  var script;
  
  //check for already loaded scripts and so they're not loaded again
  for(s in script_list)
  {
    if(loaded_scripts.indexOf(script_list[s]) == -1)
      loading_scripts.push(script_list[s]);
  }
  
  //if all the requested scripts are already loaded, callback and return
  if(loading_scripts.length == 0)
  {
    callback();
    return;
  }
  
  for(s in loading_scripts)
  {
    script = loading_scripts[s];
    $.getScript(script,  function() {
      //when script is loaded, remove it from the loading scripts array.
      //if it's the last script on the array, it means we're done loading, so call the callback function.
      loading_scripts.splice(loading_scripts.indexOf(script), 1);
      loaded_scripts.push(script);
      if((loading_scripts.length == 0) && (callback !== undefined))
 callback();
    });
  }
}
Un ejemplo de uso es el siguiente:
$(window).load_scripts(['/js/load_this.js', '/js/binder.js'], function() {
    $('#contenedor').click(function(event){
        $("#contenedor").append("hola");
    });
});
Espero que la función les sirva, al menos como ejemplo, ya que por lo que vi es un problema recurrente en los foros. Si encuentran algún error en el código, me avisan en los comentarios ;)
Tips (PHP): Escribir en la sesión de otro usuario
Mientras desarrollaba una nueva funcionalidad para el framework PHP en el que estoy trabajando, me encontré con la necesidad de realizar una acción no muy común: escribir valores en la sesión de otro usuario.

Como todo desarrollador PHP sabe (o debería...), es posible almacenar valores que persisten entre requests en una misma sesión, utilizando el arreglo súper global $_SESSION. Cada sesión se asocia a un usuario, por lo que los valores almacenados para un dado usuario son accesibles sólo para él. Ahora, y si desde la sesión de un usuario, deseamos acceder valores de la sesión de otro usuario?
Muchos se preguntarán, para qué querría hacer esto? Bueno, en mi caso particular me sirvió para actualizar la configuración de un usuario desde un usuario administrador, sin la necesidad que el primero se loguee nuevamente para ver los cambios. Por ejemplo, si un usuario administrador A cambia el theme de un usuario B que ya está logueado, quiero que B vea los cambios al instante. Podría hacer esto mismo almacenando un valor en la base de datos y chequeando desde la sesión de B el registro en cada acceso, pero esto me pareció muy ineficiente. Mi solución fue escribir un flag en el arreglo de sesión de B, y luego desde B chequear el valor en el arreglo para ver si hay cambios.
Como me resultó una funcionalidad interesante, decidí compartirla.

Para que el siguiente código funcione, es necesario almacenar los IDs de sesión de cada usuario logueado. Lo pueden hacer guardando los IDs en una tabla cada vez que un usuario se loguea en el sistema. Asumo que la función "get_user_session_id($user)" ya está implementada y me permite obtener el ID del usuario que le envío por parámetro; cada uno verá como almacenar y obtener el ID.
Traté de dejar el código lo más genérico posible, con lo que deberán cambiar sólo la línea que asigna el valor en la sesión del otro usuario, la cual marqué con el comentario "CAMBIAR AQUI!".
Espero que les resulte útil!

//guardar el session id actual para poder restaurarlo luego
$current_id = session_id();

if(($sid = user_get_session_id($user)) === FALSE)
{
  throw new Exception("user ID not found");
}

//guardar los valores de la sessión actual antes de cambiar de sessión
session_write_close();

//abrir la sessión del otro usuario
session_id($sid);
session_start();

//almacenar el valor deseado en la sessión del otro usuario
$_SESSION['some_value'] = $value;   // CAMBIAR AQUI!

//guardar los cambios hechos en la sessión del otro usuario
session_write_close();

//volver a la sessión del usuario actual
session_id($current_id);
session_start();