views:

362

answers:

2

I have a number of dropdowns and divs that are hidden when the page loads and can be toggled with a click or mouseover, but some of them flash b/c the javascript does not run in time. I have their display initially set to block and then I use javascript/prototype to find the element and hide it. I have tried loading these "hider" functions using dom:loaded but there is still flashing. This is an example of a dropdown prototype initialization funtion. From http://www.makesites.cc/programming/by-makis/simple-drop-down-menu-with-prototype/:

var DropDownMenu = Class.create();
  DropDownMenu.prototype = {
     initialize: function(menuElement) {
    menuElement.childElements().each(function(node){
      // if there is a submenu
      var submenu = $A(node.getElementsByTagName("ul")).first();
      if(submenu != null){
        // make sub-menu invisible
        Element.extend(submenu).setStyle({display: 'none'});
        // toggle the visibility of the submenu
        node.onmouseover = node.onmouseout = function(){
          Element.toggle(submenu);
        }
      }
    });
  }
};

Is there a better way to hide div's or dropdowns to avoid this flashing?

A: 

Set the display initially to none, then show them as needed. That will get rid of the flashing.

Robusto
When I try this, it seems the I am unable to find the element in the DOM using the $() method.
TenJack
According to the Prototype docs: "Element.show cannot display elements hidden via CSS stylesheets. Note that this is not a Prototype limitation but a consequence of how the CSS display property works."
TenJack
+1  A: 

You always run the risk of flicker when you try to hide elements after page load. I suggest you give the elements in question an inline style like display:none; or a css class with the same setting.

From the class creation syntax used, I take it that you are using something like Prototype version 1.5.x. Here's my take on how I'd do it with that version (it would be nicer to step up to the latest version, of course):

    <script type="text/javascript">
var DropDownMenu = Class.create();
DropDownMenu.prototype = {
  initialize: function(menuElement) {
    // Instead of using 2 listeners for every menu, listen for
    // mouse-ing on the menu-container itself.
    // Then, find the actual menu to toggle when handling the event.
    $(menuElement).observe('mouseout', DropDownMenu.menuToggle);
    $(menuElement).observe('mouseover', DropDownMenu.menuToggle);
  }
};
DropDownMenu.menuToggle = function (event) {
  var menu = DropDownMenu._findMenuElement(event);
  if (menu) {Element.toggle(menu);}
};
DropDownMenu._findMenuElement = function (event) {
  var element = Event.element(event);
  return Element.down(element, 'ul');
}
var toggler = new DropDownMenu('menus');
</script>

And here is some markup to test it with (it may not match yours perfectly, but I think it is similar enough):

<html>
<head>
<title>menu stuff</title>
<style type="text/css ">
  /* minimal css */
  #menus ul, .menu-type {float: left;width: 10em;}
</style>
</head>

<body>
<h1>Menus</h1>
<div id="menus">
  <div class="menu-type">
    Numeric
    <ul style="display: none;">
      <li>1</li><li>2</li><li>3</li><li>4</li>
    </ul>
  </div>
  <div class="menu-type">
    Alpha
    <ul style="display: none;">
      <li>a</li><li>b</li><li>c</li><li>d</li>
    </ul>
  </div>
  <div class="menu-type">
    Roman
    <ul style="display: none;">
      <li>I</li><li>II</li><li>III</li><li>IV</li>
    </ul>
  </div>
</div>
</body>
</html>

Yoda voice: "Include the prototype.js, I forgot."

Should you want to get rid of inline styling (like I do), give the uls a class like

.hidden {display:none;}

instead, and make the DropDownMenu.menuToggle function do this

if (menu) {Element.toggleClassName(menu, 'hidden');}

instead of toggling the display property directly.

Hope this helps.

npup
This looks great! Thanks a lot. I am using the latest version of prototype(1.6.1?), that was just some code I found somewhere. What would that change?
TenJack
Class creation syntax is smoother: var DropDownMenu = Class.create({ initialize: function (initObj) { this.obj = initObj; }}); // "DropDownMenu.prototype" stuff is hiddenAnd I can use event.findElement() (method on the event itself) to find the element, which also feels smoother to me. (As opposed to using "static" method calls like "Event.element(event)").
npup