Arrays asociativos en javacript

En javascript se llama array asociativo a aquellos que en vez de estar organizados con indices numericos en funcion de su posicion dentro del array, están organizados por claves no numericas.
Este tipo de arrays puede ser muy útil si tenemos listas de objetos que poseen un identificador.

  1. <br />
  2. var array_asociativo =  new Array();<br />
  3. array_asociativo['uno'] = 'brinkindans';<br />
  4. array_asociativo['dos'] = 'crusaito';<br />
  5. array_asociativo['tres'] = 'maiquel yason';<br />
  6. array_asociativo['cuatro'] = 'robocó';</p>
  7. <p>alert(array_asociativo('tres')); // -->  maiquel yason<br />

Como se puede obervar este tipo de arrays se acerca mas al concepto de Map que al de Array.
Esto ocurre porque los arrays en javascript heredan de la clase Object.
El codigo anterior seria equivalente a este:

  1. <br />
  2. var array_asociativo =  new Object();<br />
  3. array_asociativo.uno = 'brinkindans';<br />
  4. array_asociativo.dos = 'crusaito';<br />
  5. array_asociativo.tres = 'maiquel yason';<br />
  6. array_asociativo.cuatro = 'robocó';</p>
  7. <p>alert(array_asociativo('tres'))//-->  maiquel yason<br />

En ambos casos podemos acceder a sus propiedades utilizando la notación de paréntesis o la notacion de puntos.

  1. <br />
  2. alert(array_asociativo('uno')); //-->  brinkindans<br />
  3. alert(array_asociativo.dos)//-->  crusaito<br />

El principal problema con estos arrays viene cuando queremos iterar por ellos. Al no estar organizados por indices, no nos vale el típico "for( i=0; i Deberemos usar un "for in"

  1. <br />
  2. for(var i in array_asociativo) {<br />
  3.   alert(i)// Nombre de la clave<br />
  4.   alert(array_asociativo(i)); // valor<br />
  5. }<br />

Sin embargo al iterar de esta forma no solo se enumeran las propiedades del objeto en cuestión, si no también sus funciones por lo que deberíamos hacer una comprobación de tipos mediante el operando "typeof". Este operando devuelve un String con el tipo del operador sobre el que se ejecuta.
Aqui están los resultado al ejecutar el operador "typeof" sobre cada uno de los tipos de javascript.

  1. <br />
  2. typeof new Object() //-->   'object'<br />
  3. typeof new Array() //-->     'object' , ya que los arrays heredan de los objetos<br />
  4. typeof alert //-->   'function', ya que alert() es una función<br />
  5. typeof 'cadena' //-->   'string', ya que 'cadena' es un String<br />
  6. typeof 21 //-->   'number', ya que es un numero<br />
  7. typeof true //-->    'boolean'<br />
  8. typeof null //-->    'object', null también es considerado como un objeto<br />
  9. typeof undefined //-->    'undefined'<br />

Leave a Comment

Diferencias entre null y undefined

En javascript existen cinco tipos primitivos de datos: undefined, null, boolean, number y string.
A primera vista no se aprecia la diferencia entre los tipos undefined y null.

El tipo undefined corresponde a las variables que han sido definidas y todavía no se les ha asignado un valor.
El tipo null se suele utilizar para representar objetos que en ese momento no existen.

Sin embargo aunque son conceptos distintos el operando de igualdad los considera iguales. No así el operando typeof o el operador de igualdad estricta ===.

  1. <br />
  2. (undefined == null) //--> true<br />
  3. (undefined === null) //--> false<br />
  4. (typeof undefined == typeof undefined null) //--> false<br />

Si intentamos operar con una variable que tiene valor null, según el contexto devolverá los siguientes resultados.

  1. Boolean: false<br />
  2. Numeric: 0<br />
  3. String: “null

Si intentamos operar con una variable que tiene valor undefined, según el contexto devolverá los siguientes resultados.

  1. Boolean: false<br />
  2. Numeric: NaN<br />
  3. String: “undefined”

Leave a Comment

Extendiendo el objeto Array

Una de las mejores características de javascript es que se pueden añadir funciones a las 'clases' en cualquier momento a traves de la propiedad prototype.
Aprovechando esta capacidad podemos extender el objeto Array para añadirle funcionalidades de búsqueda y eliminación.

array.indexOf
Devuelve el indice del array en el que se encuentra el elemento. Devuelve -1 si no encuentra el elemento

  1. Array.prototype.indexOf = function(element) {
  2.   for (var i = 0; i &lt;this.length; i++) {
  3.     if(this[i] == element) return i;
  4.   }
  5.   return -1;
  6. };


array.exists

Devuelve true si el elemento se encuentra en el array, haciendo uso de la funcion indexOf

  1. Array.prototype.exists = function(element) {
  2.   return this.indoexOf(element) != -1;
  3. };

array.filter
Devuelve un array que contiene solo los elementos para los que la función pasada como argumento devuelve true

  1. Array.prototype.filter = function(fn) {
  2.   var array = [];
  3.   for (var i = 0; i &lt;this.length; i++) if(fn(this[i])) array.push(this[i]);
  4.   return array;
  5. };

array.removeIndex
Elimina todos los elementos del array que están entre los índices from y to. Si solo se especifica valor para from, se elimina solo el elemento que se encuentra en ese índice.

  1. Array.prototype.removeIndex = function(from, to) {
  2.   if (from &lt;0) return;
  3.   var rest = this.slice((to || from) + 1 || this.length);
  4.   this.length = from &lt;0 ? this.length + from : from;
  5.   return this.push.apply(this, rest);
  6. };

array.remove
Elimina un elemento del array, usando las funciones removeIndex e indexOf

  1. Array.prototype.remove = function(e) {
  2.   return this.removeIndex(this.indexOf(e));
  3. };

array.execute
Ejecuta la función fn pasandole como argumento cada elemento del array
si le pasamos el argument obj, se ejecutara la funcion fn como si perteneciese al objeto obj

  1. Array.prototype.execute = function(fn, owner) {
  2.   for (var i=0; i<;this.length; i++){
  3.     if (owner) fn.call(owner, this[i]);
  4.     else if (typeof this[i] != 'function') fn(this[i]);
  5.   }
  6. }

array.foreach
Ejecuta la función fn en cada elemento del array, pasandole como argumentos los elementos contenidos en el array args
si le pasamos el argument obj, se ejecutara la funcion fn como si perteneciese al objeto obj

  1. Array.prototype.foreach = function(fn, args) {
  2.   for (var i=0; i<this.length; i++) {
  3.     fn.apply(this[i], args);
  4.   }
  5. }

Leave a Comment

Seam y Ajax con Seam Remoting

Realizar peticiones Ajax a tus componentes en Seam es increíblemente fácil gracias al framework Seam Remoting.
Con solo añadir un par de lineas de javascript, tu componente escrito en Java se convierte en un componente javascript, pudiendo acceder a sus campos y ejecutar sus métodos asíncronamente.
En simplemente tres pasos podemos invocar a un componente y manejar la respuesta.

1) Indica los métodos que van a invocarse vía Ajax
Simplemente marca con la anotación @WebRemote los métodos que quieras invocar por Ajax.

  1. @Name("calculadora")
  2. public class Calculadora {
  3.  
  4.    private float pi = 3.14;
  5.    private float n = 10;
  6.  
  7.     @WebRemote
  8.     public int suma(float a, float b) {
  9.         return a+b
  10.     }
  11.  
  12.     @WebRemote
  13.     public int sumaConstante(float a) {
  14.         return this.n + a;
  15.     }
  16.  
  17.     // Este metodo no está marcado con @WebRemote, por lo que no se puede invocar desde javascript
  18.     public void metodoNoAjax() {
  19.     }
  20.  
  21.     public float getPi() { return this.pi;}
  22. }

Si quisieses invocar un EJB en lugar de un POJO, las anotaciones @WebRemote deberán estar en la declaración los métodos de la interface del EJB.

2) Importa los scripts necesarios
Primero debes importar el script que contiene el código que permite las llamadas remotas:

  1. <script type="text/javascript" src="seam/resource/remoting/resource/remote.js"></script>

Ahora por cada componente que contenga métodos que quieras invocar vía Ajax debes importar otro script en el que indicas el nombre del componente (el que has definido en la anotacion @Name).
Este script contiene el stub del componente, que indica los métodos a los que puedes llamar y la definición de sus tipos.
Por ejemplo, si tienes un componente anotado con @Name("calculadora") deberás incluir la siguiente linea

  1. <script type="text/javascript" src="seam/resource/remoting/interface.js?calculadora"></script>

Si quisieses acceder a más de un componente en la misma página puedes especificar varios componentes:

  1. <script type="text/javascript" src="seam/resource/remoting/interface.js?calculadora&componente2&componente3"></script>

También puedes importar el javascript de los componentes usando el tag s:remote.

  1. <s :remote include="calculadora,componente2,componente3"/>

3) Invoca el método y maneja la respuesta
Ahora podemos invocar los métodos de nuestra calculadora marcados con @WebRemote.
Para obtener los objetos javascript que representan nuestros componentes debemos hacerlo a través de Seam.Component.
En la llamada le pasamos los parámetros que tenga el método al que estemos invocando (admite sobrecarga) y un último parámetro que será la función a la que se invocará con el resultado de la invocación

  1. <script type="text/javascript">
  2.   //<![CDATA[
  3.  
  4.   function suma() {
  5.     Seam.Component.getInstance("calculadora").suma(1, 5, muestraResultado);
  6.   }
  7.  
  8.   function muestraResultado(result) {
  9.     alert(result); // --> mostrará un 6
  10.   }
  11.  
  12.    // ]]>
  13. </script>

También puedes acceder a los campos del componente que tengan un getter asignar un valor a los que tengan un setter.

  1. <script type="text/javascript">
  2.   //<![CDATA[
  3.  
  4.   var calc = Seam.Component.getInstance("calculadora");
  5.   function suma() {
  6.     calc.n = 25;
  7.     calc.sumaConstante(5, muestraResultado)
  8.   }
  9.  
  10.   function muestraResultado(result) {
  11.     alert(result);   // --> mostrará 30
  12.     alert(calc.pi); // --> mostrará 3.14
  13.   }
  14.  
  15.    // ]]>
  16. </script>

Seam Remoting también permite evaluar EL Expressions, trabajar con Collections, hacer debug de las llamadas enviadas y recibidas, suscribirse a una cola JMS.
Toda esta información y más se encuentra disponible en la documentación en inglés

Leave a Comment

Incluir código javascript en un documento XHTML

Si estás trabajando con Seam, muy probablemente estés utilizando Facelets para la vista y páginas xhtml.
Si intentas incluir código javascript en un documento XHTML directamente puede que de algunos problemas con los símbolos < ("menor que",&lt;) y & (amperstand), ya que el navegador los intentará interpretar como partes de etiquetas xhtml y dará algún error de sintaxis.

Para evitar ésto podemos escribir nuestro javascript entre etiquetas CDATA. Ésta etiqueta lo que hace es indicarle al validador de XHTML que ignore todo lo que se encuentre en su interior. El problema es que algunos navegadores no entienden la etiqueta CDATA, por lo que deberemos comentar la etiqueta CDATA. De esta forma, si el navegador no la sabe interpretar, la ignorará.

  1. <script type="text/javascript">
  2. //<![CDATA[
  3.  
  4.  alert("<Ésto & y ésto <<  es compatible con XHTML>");
  5.  
  6. //]]>
  7. </script>

Leave a Comment

Bloquear la pantalla con javascript

Hay ocasiones en las aplicaciones web que nos interesa bloquear la pantalla del navegador para impedir al usuario interactuar con la aplicación.
Un ejemplo es durante una llamada ajax que tarda un cierto tiempo y queremos mostrar el típico mensaje "loading" y poner el fondo con un tono oscuro, o para pedir nombre de usuario y contraseña.

Una solución simple para este problema consiste en poner un div que ocupe toda la pantalla y se sitúe por encima del resto de componentes. Así todos los clicks del ratón se realizarán sobre nuestro div en vez de sobre el botón que se ve debajo.
Después, mediante javascript muestras el div bloqueador. No te olvides de proporcionar alguna forma para quitar este elemento.
Estas propiedades del div se pueden especificar en una clase css

  1. .blocker {
  2. position: absolute;
  3. top: 0px;
  4. left: 0px;
  5. height:100%;
  6. width:100%;        /* hacemos que ocupe toda la pantalla a cualquier resolución*/
  7. z-index: 50;        /* lo colocamos por encima del resto de componentes*/
  8. background: url(b.png) repeat/*Color de fondo semitransparente*/
  9. }

Si queremos añadir algun mensaje o una ventana con la que se desee interactuar, solo tenemos que colocar un div que quede por encima del anterior.

  1. .popup{
  2. z-index: 100;                     /* un z-index mayor al del blocker */
  3. background-color: white/* Un color de fondo para que se vea sobre la capa anterior*/
  4. }

Ver ejemplo de bloqueo de pantalla

Si usas jQuery (o librerias similares) dispondrás de buenos plugins (como facebox) para hacer esto mismo con muchas mas opciones y efectos.

Leave a Comment

checkbox y evento onclick

Si alguna vez has usado la funcion toggle de jQuery con un checkbox habrás comprobado que las acciones del toggle se ejecutan, pero el checkbox no se marca (o no se desmarca).
Esto ocurre porque estamos reemplazando el comportamiento nativo del checkbox por el nuestro propio. Para evitar este comportamiento, debemos registrar el listener con el evento onchange o el evento onclick. (NOTA: Parece ser que internet explorer 6 no maneja bien el evento onchange).

Para solucionar este problemilla, podemos escribir nuestra propia función toggle para checkboxes:

  1. $('#checkbox').click(function(){
  2.   if (this.checked) alert('checkbox activado');
  3.   else alert('checkbox desactivado')                
  4. });

Aqui puedes ver un ejemplo completo

Comments (2)

XML, tildes y javascript

Al leer un documento xml codificado en UTF-8 que contiene tildes o eñes con javascript, las interpretará como simbolos extraños .
Para solucionar este problema se debe establecer la codificacion en latin9 (ISO-8859-15), modificando la primera linea del archivo XML.

  1. <?xml version="1.0" encoding="ISO-8859-15"?>

Leave a Comment