Apagando elementos “select” en Internet Explorer

Visita este artí­culo en http://www.estadobeta.com/2006/08/09/apagando-elementos-select-para-ie/

Por Ismael en artículos, javascript, tips

Tips para solucionar un molesto problema de Internet Explorer con un poco de javascript.

¿has invertido horas en construir delicados DIVs que flotan sobre tu página web, tal vez un menu desplegable o un panel de resultados Ajax, sólo para descubrir que en Microsoft Internet Explorer los elementos <select> aparecen siempre sobre los <div> flotantes?

Yo también.

El problema es común y sucede porque, en IE, los elementos <select> son “rendereados” (dibujados en pantalla) directamente por Windows y no por el navegador. Una de las consecuencias no previstas de la <sarcasmo>brillante</sarcasmo> idea de hacer IE tan integrado al sistema operativo.

La solución, o más bien parche, para este inconveniente es esconder los <select> antes de desplegar otros elementos sobre ellos, y volver a mostrarlos al esconder los elementos flotantes.

Esto se hace con javascript, y una forma común es algo así:


function escondeSelects(){
    if(!window.attachEvent) return false;
    var selects = document.getElementsByTagName(”select“);
    for( var i=0; i<selects .length; i++ ){
        selects[i].style.display = “none“;
    }
}

La primera línea de la función (if(!window.attachEvent) return false;) revisa que exista el método attachEvent del objeto window. Este método sólo existe para la versión no estándar del DOM de IE, por lo tanto si el método no existe no es necesario esconder los <select> y la función detiene su ejecución.
La función escondeSelects() obtiene todos los elementos <selec> en un array usando el método del DOM estándar document.getElementsByTagName(), que retorna todos los elementos HTML que correspondan a la etiqueta pasada como argumento. Luego hace un loop sobre esa colección usando for y actualiza la propiedad style.display de cada elemento al valor “none”, haciendolo invisible.

Ahora basta con llamar a escondeSelects() antes de mostrar elementos flotantes sobre la página.

La función para volver a encender los elementos es similar pero retorna la propiedad style.display al valor “inline”, default para los <select>.

Ahora, si estas usando la librería Javascript Prototype.js podrías usar la espectacular función $$(), que recibe un selector CSS, y hacer algo como esto:


$$(“select”).each( function(select){select.hide()} );

Y para volver a mostrar:


$$(“select”).each( function(select){select.show()} );

Espero que se note la elegancia de esta última solución con respecto a la primera. Prototype.js nos ayuda a reducir nuestro código miestras esperamos las bondades del nuevo Javascript.

javascript, prototype, web development, DOM

12 comentarios para “Apagando elementos “select” en Internet Explorer”

  1. Gravatarvladimir prieto Dice:

    bueno el dato.

    yo me sabía otro, y era poniendo un iframe detrás los los “elementos flotantes”, de manera que el iframe se esconde por el div del elemento flotante. asi se logra el mismo efecto.

  2. GravatarCoto Dice:

    Estupendo dato, este prototype, nunca termino de conocerlo!!

  3. GravatarJonathan Snook Dice:

    Pardon my lack of spanish but since you’re using Prototype 1.5 you could simplify your code.

    change Element.hide(select) to select.hide();

  4. GravatarIsmael Dice:

    Jonathan: thanks for stopping by (what an honor!).
    You are absolutely right. I explain the two interfaces in this article (in Spanish), but for this example I stuck with the one I’m more used to. It is corrected now.

    En castellano: Jonathan dice que, desde la versión 1.5 de Prototype, la línea

    Element.hide(select)

    Se puede resumir en

    select.hide()

  5. GravatarMañungo Dice:

    Lo más elegante sería escribir… $$(’select’).each( Element.hide );… pero no funciona ( por qué ? propuesto al gentil lector :P )

  6. GravatarIsmael Dice:

    Mañungo:
    Array.each() tiene que recibir de argumento una función, que se ejecuta una vez por cada elemento del array (en este caso los elementos son los selects de la página). Esa función “iteradora” recibe a su vez el elemento correpondiente como argumento.

    Entonces, el método hide() tiene que ser invocado sobre cada elemento del array. El objeto Element de Prototype es sólo un objeto que agrupa funciones relacionadas al manejo del DOM, y no representa a los selects de nuestro array $$("select").

    Por otro lado, no es lo mismo Element.hide que Element.hide(). hide() es un método (una función perteneciente a un objeto) y los paréntesis son necesarios para ejecutarla y pasarle argumentos.

  7. GravatarMañungo Dice:

    Ismael:

    En realidad $$(’select’).each( Element.hide ); se cae a medias: each invoca a Element.hide con los parámetros Element.hide( select, index ); esto funciona bien para el select, pero se cae para el index que es solo un numero (no un Element).

    Si haces $$(’select’).each( alert ); verás que aparecen alerts para cada select sin los index porque alert está preparada para recibir sólo un argumento, e ignora el segundo. Si Element.hide fuera igual, mi idea funcionaría ok.

    Mirando el código de Prototype, veo varias formas de resolverlo, pero claro, eso sería modificar la librería. De hecho, esto de andar creando taaaaaaaaaantas funciones anónimas, me aburre enormemente de Prototype :(

  8. GravatarIsmael Dice:

    Tienes razón, con unos ajustes a Element.hide() se podría usar como función iteradora para Array.each(), Por supuesto, siempre puedes sobreescribir areas parciales de Prototype en tu propio archivo JS.
    Los métodos iteradores de Prototype tienen sentido el algunos casos puntuales (cuand ahorran código y ganan en legibilidad). Para otros casos basta con usar los iteradores nativos de Javascript (que además son más rápidos). Array.each trata de “emular” los bloques de Ruby, donde puedes hacer cosas como

    
    mi_array.each {|elemento|
        //haz algo con el elemento
    }
    
    

    Básicamente, se pasa un “bloque” de código a each().
    En Javascript el concepto de bloque no existe y por lo tanto se pasa una función completa, que aumenta la cantidad de código y crea problemas de “scope” que deben ser solucionados con otros métodos de Prototype (function.bind() y function.bindAsEventListener()).
    Espero que se haya entendido algo :(

  9. Gravatarenzoscuro Dice:

    Sin prototype como podria ser, que lata anxarle 50 kilos extras a la pagina solo para esconder un par de select

    un saludo

  10. GravatarIsmael Dice:

    Enzoscuro, la primera versión de la función en este mismo artículo no usa Prototype. La versión con Prototype sólo tiene sentido si ya estas usando la librería para otras partes de tu aplicación.

  11. Gravatarenzoscuro Dice:

    Claro, disculpnme mi cegera, Ismael podrias hablar un poco de Comet

  12. GravatarAplicacionesWeb » Blog Archive » Apagando “select” en IE Dice:

    […] Via EstadoBeta.com […]

Deja un comentario

XHTML: puedes usar estas etiquetas: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>