Archivo de la categoría: Javascript

jquery-logo

jQuery: .css(“background-position”) falla en Internet Explorer

Me iba a poner a explicar porque falla y todo lo que tuve que hacer hasta darme cuenta del problema y la forma de solucionarlo, pero prefiero por esta vez simplemente dejarles la función que hice para arreglar el problema:

El siguiente método se acopla a jQuery por lo que lo pueden cargar justo después de jQuery y usarlo normalmente.

/**
 * Devuelve un array con la posicion X e Y respectivamente.
 */
$.fn.bgPosition = function() {
    var bgp = "background-position";
    return $.browser.msie ? [parseInt($(this).css(bgp + "-x").split(" ")[0]), parseInt($(this).css(bgp + "-y").split(" ")[0])] : [parseInt($(this).css(bgp).split(" ")[0]), parseInt($(this).css(bgp).split(" ")[1])];
}

Y como mencione, el uso es bastante sencillo.

//Para usarlo:
alert("las posiciónes X e Y del fondo son: " + $("#cajaConFondo").bgPosition()); //muestra [posX, posY]
alert("La posición X del fondo es: " + $("#cajaConFondo").bgPosition()[0]); //muestra posX
alert("La posición Y del fondo es: " + $("#cajaConFondo").bgPosition()[1]); //muestra posY

Para cerrar el post el problema en resumen es que internet explorer no reconoce la propiedad “background-position” del metodo .css(). En su lugar hay que usar “background-position-x” y “background-position-y

Y una cosita mas: el método solo funciona con pixeles porque es lo que me hacía falta, porcentajes y demases yerbas quedan excluidas salvo que alguien quiera aportar esa parte ;)

Descargar ejemplo

Druplicon

Drupal: Porque usar Drupal.behaviors en lugar de $(document).ready();

Durante mucho tiempo estuve usando $(document).ready(); para poner mi js en Drupal, y funcionaba la mar de bien. Esto me permitía ejecutar javascript inmediatamente después que el DOM estuviera cargado evitando así errores de referencias a objetos que todavía no existieran al querer manipularlos.

Ahora bien, hay un problema que vamos a encontrar por medio de un ejemplo simple:

Si tuviéramos un listado de nodos y a ese listado hiciéramos que al pinchar sobre sus enlaces hiciera un alert de su atributo “title” usando jQuery:

jQuery(document).ready(function($) {
    $("#listado_de_nodos a").click(function(e) {
        alert($(this).attr("title"));
    });
});

¿Qué pasa si por medio de AJAX se agregaran nuevos nodos? te lo digo, que no reaccionarían al hacer click sobre ellos, y es por que el método .click() de jQuery se ejecuta una sola vez en busca de elementos que macheen con su criterio y una vez finalizado ya está, no hace mas. Es un comportamiento de lo mas entendible ya que imaginemos que estuviera escaneando constantemente por nuevos elementos ese selector mas los otros 50 que estemos usando para hacer mas cosas…. Google Chrome lo soportaría sin apenas darle carga al procesador y RAM, pero piensen en la basura de IE…..

Perdonen que me vaya por las ramas, como les decía, dado el problema que se planteo para el listado de nodos que di como ejemplo, se implemento una solucion (bueno cubre mas problemas pero este es de los mas comunes) la solución fue usar al objeto Drupal.behaviors a modo de controlador. Drupal.behaviors relanza todas las funciones que almacena por cada vez que se lance una petición AJAX, dándonos la oportunidad de re procesar cosas. Así pues en el ejemplo anterior lo podemos poner dentro de un behavior para poder aplicar nuestra funcionalidad incluso a los nuevos elementos provenientes de la petición:

Drupal.behaviors.alertarEnlaces = function(context) {
    $("#listado_de_nodos a").click(function(e) {
        alert($(this).attr("title"));
    });
}

Como ven lo único que hay que reemplazar en nuestros actuales ficheros de javascript es jQuery(document).ready(function($) {}) por Drupal.behaviors.alertarEnlaces = function(context) {} y no se preocupen por el hecho de que su código este ahora asignado dentro de una función(“Drupal.behaviors.alertarEnlace() “), porque esta se ejecuta solita, y veanlo incluso como una ventaja, pueden invocarla ustedes mismos cuando quieran ademas.

jquery-logo

jQuery.height() calcula distintos tamaños entre navegadores [solución]

Este es un tip rápido pero útil.

Escenario:
Tenes un div con el id “elDiv” con el siguiente CSS:

#elDiv {
	border: 1px solid #336699;
	float: right;
	padding: 20px;
	width: 500px;
}

Y en Firefox/Chrome/Safari/Opera al hacer $(“#elDiv”).height(); te entrega 400px por decir algo (el tamaño depende de lo que tenga dentro).
Pero curiosamente en Internet explorer te da un tamaño raro… de menos, unos 358px en nuestro ejemplo.

¿Qué pasa?
Pasa que no le especificaste un modo de renderizado al HTML por medio del DOCTYPE, y por culpa de ello Internet explorer va a renderizar el contenido en modo “Quirks Modehttp://es.wikipedia.org/wiki/Quirks_Mode.

Si no queres leer el articulo de Wikipedia te comento que lo único que tenes que hacer es poner lo siguiente por encima del tag <html>:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/DTD/strict.dtd">

PD: el valor de 358px en mi ejemplo viene de que en modo quirks, IE toma el tamaño del tamaño real menos el padding y el borde: 400 - 40 - 2 = 358.

Curiosidades y cosas útiles de jQuery

En addyosmani.com encontré 31 snippets para jQuery de los cuales algunos me parecen especialmente útiles:

Método .live():
Según comentan en el blog (y tiene razón) es mas útil que usar directamente el método .click(). ¿por que?, fácil, porque el método .live() es capaz de mantenerse a la escucha de cualquier elemento que machee con el selector aun si el elemento ha sido creado después de haberlos enlazado.
Un ejemplo:

$('.clickme').click(function() {
	alert("Hola, me hiciste click");
});

El código anterior va a funcionar sobre todos los elementos que actualmente existan en el DOM, pero nos podemos ir olvidando que lo haga sobre cualquier contenido que se cree después de ese momento.

$('.clickme').live('click', function() {
        alert(“¿ves? Me sigo ejecutando sobre cualquier elemento”);
});

Aquí la diferencia: Si yo después de haber ejecutado el anterior código, hiciera:

$(“body”).append(“<a href=”#” class=”clickme” >Soy nuevo</a>);

El nuevo elemento SI ejecutaría el código.

Agrupado de funciones:
Otra de las gracias que tiene jQuery es que permite apilar funciones:

jQuery('#foo').bind({
	click: function() {
		alert(“Me haces click”);
	},
	mouseover: function() {
		alert(“Me pasas por encima”);
	},
	mouseout: function() {
		alert(“No estás mas encima de mi”);
	}
});

Se explica solo, pero por si quedan dudas lo que hicimos acá fue ahorrar código usando un único selector. Al elemento seleccionado le hemos pegado tres eventos junto a las funciones correspondientes. Geeeenial.

Método .sleep()
Siempre me hiso falta una manera de retardar algunas acciones, y de momento había estado usando query.timer.js (un plugin). Pero los tiempos cambian, y desde la versión 1,4 de jQuery ya viene esta característica incorporada.
Ejemplo:

$('#caja').slideUp(300).delay(1000).slideDown(400);

Traducción: #caja va a plegarse en 300 mili segundos, no va a hacer mas que esperar un segundo (1000 mili segundos) y va a desplegarse a lo largo de 400 mili segundos

Método .data()
Si necesitas almacenar información (temporalmente) podes usar variables.. Pero si lo que querés es “pegar” información a elementos del DOM lo que necesitas es esto.

Ejemplo:

$("div").data("nombre", 'Marcelo');
alert($("div").data("nombre") === 'Marcelo'); //imprime true

¿Para que sirve?. Está mas que claro. Si tuvieras una tabla, y a los <tr /> les quisieras establecer un id asociado…. ¿vas viendo la idea?

Shortcut para el metodología .find()

Si tenes que ir seleccionado elementos que están dentro de un elemento por lo general usamos el método .find(). Bueno resulta que podemos usar el método de una forma mas abreviada y clara:

$(“a”).find(“b”);
//podemos expresarlo como:
$(“a”, “b”);

Seleccionar elementos cuyo id contiene caracteres especiales:
si tratamos seleccionar un div que tenga en su id un par de corchetes como en el siguiente caso:

$("$item_[200]");

No va a funcionar. Pero podemos seleccionar este elemento de la siguiente forma:

$("$item_\\[200\\]");
jquery-logo

No funciona jQuery change() en Internet Explorer

La situación: Probaste en Firefox el método change de jQuery sobre un checkbox, pero cuando lo probas en IE falla, no hace caso.

Esto se debe al pésimo soporte que ofrece Internet Explorer con javascript, pero esta nota no es para hablar mal de IE, para eso ya habrá un post entero y de varias paginas :)

La solución mas acertada es mantener el método change para todo navegador que no sea IE, y usar click para IE. Lo hacemos así porque si aplicamos click sobre un checkbox en un navegador serio, este no lanza nada porque para el no es un click, es un change.

$(document).ready(function() {
    var che = $(".mi_checkbox");
    if ($.browser.msie) {
        che.click(function() {
            alert("funciono ok");
        });
    } else {
        che.change(function() {
            alert("funciono ok");
        });
    }
});
1263055255_application-javascript

Variables globales en Javascript

¿A que más de uno tuvo el mismo problema que yo?
Hablo de usar una función que tiene callback como $.post() de jQuery y no saber como recuperar los valores que se sesean en la respuesta de la petición.

Bueno es más bien de simple solución:

MAL:

$.post("urlDestino", { mandoAlgo : "cosas" },
        function(resultado) {
            var variableLocal = resultado
            return variableLocal   //--> esta variable no se va a ver jamas fuera de esta función
        }, "json");

BIEN:

var variableGlobal;
$.post("urlDestino", {
    mandoAlgo : "cosas"
},
        function(resultado) {
            var variableGlobal = resultado
            return variableGlobal
        }, "json");

Si todavía no te diste cuenta es tremendamente simple: definir las variables fuera de cualquier función. :)

jquery-logo

Hacer que un slideToggle() tenga un min-height

[Hay una version mas reciente de este plugin aquí]

Si queres hacer que un slideToggle() en jQuery que tenga un alto mínimo, te vas a dar con el siguiente problema:

Primero que slideToggle() lo que hace es partir de un div con display:none hasta el alto máximo que tenga, y no desde un alto mínimo. Segundo que si le pones un min-height la animación pega un salto de cero al min-height y desde ahí comienza la animación. por consiguiente pega un salto que no queda bien y no logramos que quede en un mínimo porque cuando lo cierres va a obviar el min-height y se va a cerrar completamente.

Resumiendo slideToggle() no nos sirve. En su lugar vi en Spoonfed Project un articulo que da el siguiente script para poder crear animación tipo slideToggle() pero con min-height:

<script type="text/javascript" src="/includes/jquery-1.4.min.js"></script>
<script type="text/javascript">
$(function(){
	var slideHeight = 75; // px
	var defHeight = $('#wrap').height();
	if(defHeight >= slideHeight){
		$('#wrap').css('height' , slideHeight + 'px');
		$('#read-more').append('<a href="#">Click to Read More</a>');
		$('#read-more a').click(function(){
			var curHeight = $('#wrap').height();
			if(curHeight == slideHeight){
				$('#wrap').animate({
				  height: defHeight
				}, "normal");
				$('#read-more a').html('Close');
				$('#gradient').fadeOut();
			}else{
				$('#wrap').animate({
				  height: slideHeight
				}, "normal");
				$('#read-more a').html('Click to Read More');
				$('#gradient').fadeIn();
			}
			return false;
		});
	}
});
</script>

Esta excelente la solución que usa aquí, pero lo convertí en plugin para los que utilizamos cositas así constantemente.

Podes ver una demo acá.

Para usarlo hacemos lo siguiente:

$('#pestania').slideToggleMinHeight({
				desplegable:"desplegable",
				min_height:80,
				});

Descargar codigo + ejemplo.