Javascript: Devolver 0 cuando parseInt() o parseFloat() reciban una cadena vacía

Tip rápido sobre Javascript: Imaginad que recogemos los datos de un formulario para que calcule en pantalla un sumatorio conforme el usuario los va introduciendo. Ahora imaginad que el usuario se deja un campo vacío. Cuando la función javascript se encuentre una cadena vacía, e intente convertirla a un número (con parseInt() o parseFloat() según lo que necesitemos) el resultado de la suma será NaN. ¿Cómo lo evitamos? Pues con un OR.

Si utilizamos el operador || seguido de un cero, tal como está en el ejemplo que verás a continuación, este evaluará de forma lógica la expresión, y en caso de que el primer término evaluado sea falso devolverá el segundo, un cero (el resultado NaN que devolverá la función que parse a número será evaluado como falso):

var s = '';
var total = 1;

//Si hago esto, el resultado es NaN
total = total + parseInt(s);

//Si hago esto, el resultado es 1
total = total + (parseInt(s) || 0;);

//con parseFloat funciona igual

Otra opción, utilizar el operador ternario ?:, como pusimos en otro ejemplo pasado.

jqPlot: mostrar la leyenda en varias columnas

El otro día trabajaba con la librería jqPlot, una librería para crear gráficas por medio de javascript y jQuery, y me encontraba con que la leyenda de un gráfico de tarta que estaba haciendo se salía de su elemento contenedor, dado que tenía muchas líneas (en concreto, 58). Me pregunté ¿Cómo hago para que se muestre en dos columnas?. Pensé que era obvio que a alguien le habría pasado ants y encontré la solución en stack-overflow:

//La localización no es importante, sólo el 
//rendererOptions
legend: { 
  show: true, 
  location: 'ne',
  rendererOptions: {numberColumns: 2}
}

Luego decidí bucear un poco más en la documentación y me encontré con un plugin que nos dará mayor versatilidad para trabajar con la leyenda: jqplot.enhancedLegendRenderer.js

La cuestión es invocarlo dentro de la configuración de la leyenda y, además de permitirnos definir el número de filas y columnas (cosa que ya podemos hacer con el renderer normal, pero en este han pulido algunos bugs) también nos permite ocultar/mostrar una serie al pinchar en la leyenda. Se me ocurrió usarlo para mostrar los resultados debajo de la gráfica, en 6 columnas de 10 filas, para que quedara más bonito. Total, que la cosa fue así:

//La localización no es importante, sólo el 
//rendererOptions
legend: {
  renderer: $.jqplot.EnhancedLegendRenderer, 
  show: true, 
  location: 's',
  rendererOptions: {numberColumns: 10, numberRows: 6}
}

Función para convertir valores NaN en 0 en Javascript

Vamos como una minientrada sobre Javascript. Hoy trabajaba con varios sumatorios y en algún momento me «rompía» la cuenta porque intentaba acceder al valor de un campo vacío, recibía un valor NaN… El resultado es que toda la cuenta se iba al carajo.

Javascript nativamente nos ofrece una función llamada isNaN() para comprobar si una variable tiene ese valor (en caso de que lo tenga devolverá un true), por lo que sirviéndonos de ella podemos crear una función que nos devuelva un 0 cuando el valor sea NaN. Tal que así:

function NaN2Zero(n){
    return isNaN( n ) ? 0 : n; 
}

Dicha función llama a isNaN para comprobar el valor. En caso de respuesta afirmativa devuelve un 0, en caso contrario devuelve el valor de la variable recibida.

Crear un elemento arrastrable (drag and drop) con jQuery, sin jQuery UI

jQuery UI nos permite definir un elemento como «draggable» para que podamos «agarrarlo» con el ratón para arrastrarlo por la pantalla y situarlo donde mejor nos convenga. Hoy en el trabajo me veía con la limitación de no poder recurrir a jQuery UI, sólo podía utilizar jQuery 1.11 y tenía que lograr el mismo efecto.

Mentiría si dijera que lo hice yo, básicamente cogí este código de CSS-Tricks que os dejo a continuación y le hice un par de pequeños cambios para que funcionara de la forma deseada en la aplicación.

(function($) {
    $.fn.drags = function(opt) {

        opt = $.extend({handle:"",cursor:"move"}, opt);

        if(opt.handle === "") {
            var $el = this;
        } else {
            var $el = this.find(opt.handle);
        }

        return $el.css('cursor', opt.cursor).on("mousedown", function(e) {
            if(opt.handle === "") {
                var $drag = $(this).addClass('draggable');
            } else {
                var $drag = $(this).addClass('active-handle').parent().addClass('draggable');
            }
            var z_idx = $drag.css('z-index'),
                drg_h = $drag.outerHeight(),
                drg_w = $drag.outerWidth(),
                pos_y = $drag.offset().top + drg_h - e.pageY,
                pos_x = $drag.offset().left + drg_w - e.pageX;
            $drag.css('z-index', 1000).parents().on("mousemove", function(e) {
                $('.draggable').offset({
                    top:e.pageY + pos_y - drg_h,
                    left:e.pageX + pos_x - drg_w
                }).on("mouseup", function() {
                    $(this).removeClass('draggable').css('z-index', z_idx);
                });
            });
            e.preventDefault(); // disable selection
        }).on("mouseup", function() {
            if(opt.handle === "") {
                $(this).removeClass('draggable');
            } else {
                $(this).removeClass('active-handle').parent().removeClass('draggable');
            }
        });

    }
})(jQuery);

Tras esto me bastó aplicar esa función sobre los elementos deseados, en ese caso por medio de una clase:

$('.ElementoMovil').drags();

En este caso dad gracias a esa excelente web que es CSSTricks cargada de trucos para mejorar el diseño y la experiencia del usuario, ya que el trabajo es suyo. En el artículo original podéis probar el funcionamiento de dicha función. Añado que en versiones muy antiguas de jQuery no funciona, al menos con 1.5.2 que fue con la que lo probé en principio. En cualquier caso, es recomendable tener siempre esta librería actualizada.

Hacer un window.open() en segundo plano

Vamos con un tip rápido de javascript ¿Cómo hago un window.open(), en una ventana nueva, de forma que la ventana nueva se sitúe detrás de la principal y no delante? Hay dos opciones:

Bueno, empezando por el principio, recordad que para que se abra en nueva ventana debéis añadir el parámetro «_blank» tal que así:

window.open('emergente.php', '_blank'); /*y ya luego le metéis las variables extra que os apetezca*/

Entonces ¿cómo lo mandamos a segundo plano?

  • Opción a: Centrando el foco en nuestra ventana principal, añadiendo la línea self.focus(); tras el window.open().
  • Opción b: Sacando el foco de la nueva ventana abierta, añadiendo en la cabecera el siguiente script:

    <script languaje="javascript">
      self.blur();
    </script>
    

Clases para imágenes en Twitter Bootstrap

Hacía tiempo que no tocaba un post «por encargo», pero me han comentado por Twitter que hable de las clases que el framework Bootstrap nos ofrece para trabajar con imágenes. No son muchas, la verdad, y de hecho están recogidas en su documentación oficial. Pero en fin, allá vamos.

Básicamente, en cuanto a la forma de la imagen, Bootstrap nos ofrece tres clases para tres resultados distintos: rounded, circle y thumbnail. La primera hará que la imagen tenga bordes redondeados, la segunda que esta sea circular y la tercera le pondrá un marco alrededor. El ejemplillo en código sería:`

<!--Bordes redondeados-->
<img src="carpeta/archivo.extension" alt="Texto1" class="img-rounded">
<!--Circular-->
<img src="carpeta/otroarchivo.extension" alt="Texto3" class="img-circle">
<!--Thumbnail con marco-->
<img src="otracarpeta/archivo.extension" alt="Texto5" class="img-thumbnail">

También hay una clase para imágenes responsivas, que básicamente aplica un max-width del 100% y un height automático, lo que hace que su tamaño se adapte al de su elemento padre. En ese caso se usar la clase img-responsive:

<img src="carpeta/imagen.extension" class="img-responsive" alt="Imagen de tamaño adaptable">

Y ya está todo el pescao vendido, no hay más que rascar en este tema (aunque sí en Bootstrap, un estupendo framework para el desarrollo de front end)

Acceder a los elementos de un Iframe con Javascript

Un tip rápido de Javascript: Tienes un iframe en tu página y quieres acceder a los elementos que hay dentro. ¿Es posible hacerlo? Sí pero no. Me explico:

Si el iframe está en el mismo dominio que la página padre sí, si no, por motivos de seguridad, el navegador no te lo permitirá.

En caso de que la respuesta a si está en el mismo dominio sea afirmativa puedes acceder al iframe por su id, ya que habrá un objeto donde estarán guardados todos, y una vez accedido a él puedes llegar a sus elementos a través de su id. Un ejemplo simple:

// cambia miFrame por el id de tu iframe,
// cambia idDelElemento por el id que corresponda,
// puedes trabajar con los elementos del iframe como si fueran parte de la página padre.
window.frames['miFrame'].document.getElementById('idDelElemento')

Añadiendo elementos al DOM con Javascript: appendChild e insertBefore

Una de las funcionalidades potentes de Javascript es poder generar nuevo código dinámicamente y añadirlo a nuestra web, cosa que podemos hacer con las funciones appendChild e insertBefore.

El método appendChild nos permite insertar un elemento dentro de otro, al final del mismo. Imagina que quieres agregar un elemento a una lista que sea «nuevo elemento«, pues javascript permite crear este nuevo elemento, meterle un nodo de texto y agregarlo a la lista. Veamos como:

elemento1 = document.createElement('li');
elemento1.appendChild(document.createTextNode('nuevo elemento'));
elemento2 = document.getElementById('laListaQueYaExiste');
elemento2.appendChild(elemento1);

¿Y si quieres insertar al principio en lugar de al final de la lista? Pues tan simple como usar insertBefore:

elemento1 = document.createElement('li');
elemento1.appendChild(document.createTextNode('nuevo elemento'));
elementoLista = document.getElementById('laListaQueYaExiste');
//hasta aquí todo igual
elemento2 = elementoLista.firstChild();
//en la línea de arriba creamos un elemento nuevo que es el primer elemento de la lista.
elemento3.parentNode.insertBefore(elemento1,elemento3);
//también podríamos haberlo hecho así:
elementoLista.insertBefore(elemento1,elemento3);

Detectar si un usuario usa Adblock Plus

El tema de la publicidad en internet está candente últimamente. Por un lado algunas páginas se pasan de publicidad intrusiva (y no hablo sólo de sitios donde ver retransmisiones deportivas on-line, basta con entrar en la web de cualquier periódico español «grande» para ver anuncios que a veces hasta dificultan la lectura), pero por otra parte también están muchas webs gratuitas cuya única fuente de ingresos es la publicidad, y al bloquearla les dejamos sin un dinero necesario para pagar los gastos ocasionados. Algunas web optan por bloquear a los usuarios que llegan con el adblock puesto, yo no comparto estas medidas draconianas ya que soy el primero que ve eso y lo siguiente que hace es salir de la página y buscar otra que me ofrezca lo mismo sin esta publicidad. Creo que la mejor solución sería el «buenrollismo«, vamos, que si se detecta en AdBlock se le saca al usuario un aviso tipo «tío, que alojamiento y dominio son 50 pavos anuales, que no es mucho pero me los sacaba con estos anuncillos de google, no me jodas y saca el bloqueador, man». La mayoría no te harán ni caso, pero bloqueándoles no te creas que lograrías mejores resultados, al menos así puede que lo compartan en redes sociales y logres ingresos de otros usuarios que lo miren.

Vamos pues con la chicha ¿cómo se detecta AdBlock? Bueno, yo lo he hecho mediante el método del señuelo, que de momento va furrulando. La cuestión es que AdBlock tiene una lista negra de palabras y bloquea según qué javascript si detecta alguna de ellas. El truco es meter un javascript con un nombre que haga saltar Adblock, comprobar que dicho javascript no está furrulando y, en ese caso, lanzar un aviso al usuario.

Empezamos creando un archivo de javascript con el título advertisement.js, un nombre que hará saltar a Adblock para evitar su carga, con un contenido más o menos como el siguiente:

document.write('<div id="le_truquito">Publicidad malvada y terrible!!</div>');

La idea es hacer el document.write de un div con un id concreto, lo del texto ya es chorrada mía. Por si entra un usuario sin Adblock lo mejor es que ocultemos ese div que se creará con CSS, para que no le aparezca por medio.

#le_truquito{
    display:none;
}

Ok, lista la trampa lo siguiente es añadir otro código de javascript que comprobará si se ha bloqueado el primero (cerciorándose de si existe el div que debería crear) y, en caso de que no lo haya hecho sacará un mensaje en pantalla.

<script type="text/javascript">
if (document.getElementById("le_truquito") == undefined)
{
    window.alert("tío, que alojamiento y dominio son 50 pavos anuales, que no es mucho pero me los sacaba con estos anuncillos de google, no me jodas y saca el bloqueador, man");
}
</script>

En el ejemplo puse un window.alert, pero también podéis crear un div con un texto en la página… en fin, lo que veáis más práctico.

De momento el sistema funciona, y tiene pinta de que al menos durante una temporada lo hará. En todo caso podéis buscar el nombre de un archivo de javascript de publicidad de Google, o de otra compañía, que sepáis positivamente que se está bloqueando por AdBlock y llamarle así en lugar de advertisement.js (aunque de momento con ese nombre furrula).

Redireccionar y recargar web con javascript

Todavía está virgen 2014 de alguna entrada sobre informática, al empezar el año de vacaciones me dediqué a temas más ociosos. Vamos pues con una minientrada sobre javascript ¿cómo redireccionar una web usando este lenguaje?

Empecemos por un punto, existen muchas formas de hacer redirecciones, tanto desde el servidor como desde el cliente. Hasta con una mera etiqueta en HTML podemos hacerlo. Vamos a ver cómo se puede hacer desde javascript dado que tiene mucha chicha. Para ello nos serviremos del objeto Location.

Para ir a una URL determinada lo más sencillo es usar la propiedad href de location. Con href podremos tanto recuperar la url en la que navegamos como cambiar el valor de la misma. Podemos usar una url absoluta para ir a otra web externa a la nuestra o una relativa para navegar dentro de nuestra web:

/*Ruta absoluta, nos llevaría a una web externa*/ 
location.href = "http://www.webquequeremosver.com"; 
/*En cambio esta nos llevaría a una dentro de nuestro dominio*/ 
location.href="admin.php";

Otra opción son los métodos replace y assign. Ambos hacen que location cargue un nuevo documento, pero con una diferencia: replace quita el sitio actual de la historia de navegación del documento, de esa forma el botón «atrás» del navegador no puede utilizarse para volver a la página anterior. En cambio assign simplemente carga el nuevo documento, por lo que sí tendrás esa función de navegar hacia atrás activa.

/*Con replace nos vamos a un nuevo document y bloqueamos el botón de atrás*/
location.replace("http://google.es"); 
/*Con assign en cambio conservamos esa funcionalidad*/ 
location.assign("http://google.es");

¿Y para recargar la página? Pues está el método reload, el cual por defecto recargará desde la caché a no ser que le pasemos el parámetro true para forzar la recarga desde el servidor. Es decir, el método por defecto funcionaría como la tecla F5 en vuestro navegador, y con el true en cambio lo haría como ctrl+F5

/*Recargamos desde caché*/ 
location.reload(); 
/*Forzamos la recarga*/ 
location.reload(true);