tags:

views:

60

answers:

3
+1  Q: 

Javascript Blur

I'm in the process of learning Javascript and I'm trying to create a simple dropdown menu. An example of my desired functionality can be seen on the google homepage in the top menu with the "more" and "settings" dropdown.

I have a ul that is set to display:inline using the onclick() JS event handler. How do I make the ul go back to display:none when I click any where else on the page other than the now visible ul?

I've Googled about blur and setting the focus to another element but I don't know how to actually do it.

I want to do this in straight Javascript, not jQuery.

Here is the html I use:

<div class="info">  
     Some Text Boom A <a  onclick="menu('id1');">Link</a> | More text 
     <a onclick="menu('id2');">Another Link</a> | more text 
     <ul id="id1" class="submenu">  
       <li><a href="dfhdfh">A1</a></li>  
       <li><a href="aetjetjsd">A2 This is Long</a></li>  
       <li><a href="etetueb">A3</a></li>  
     </ul>  
    <ul id="id2" class="submenu">  
       <li><a href="dfhdfh">B1</a></li>  
       <li><a href="aetjetjsd">B2</a></li>  
       <li><a href="etetueb">B3</a></li>  
     </ul>  
  </div> 

When the user clicks on one of the linked <a> tags, the <ul> which is hidden and directly below the <a> tag becomes visible. I want the <ul> element to dissapear when the user clicks anywhere but the <ul>.

Edit:

Here is my javascript:

function menu(id) {  
    var myLayer = document.getElementById(id);  
    if (myLayer.style.display == "none" || myLayer.style.display == "") {  
        myLayer.style.display = "block";  
    } else {  
        myLayer.style.display = "none";  
    }  
} 

Edit 2:

Complete CodE:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;

<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>Untitled 1</title>

<style type="text/css">
a
{
    color:blue;
}

.info ul.submenu
{
    border: solid 1px #e0e0e0;
    background-color: #fff;
    position: absolute;
    padding: 0;
    z-index: 2;
    display: none;
}

.info ul.submenu li
{
    display: block;
    border-top: solid 1px #e0e0e0;
    margin: 0px 10px 0 10px;
}

.info ul.submenu li a
{
    display: block;
    padding: 7px 0px 6px 0;
    color: #1177ee;
    cursor:pointer;
}

</style>

<script type="text/javascript">

function menu(id) {   
    var myLayer = document.getElementById(id);   

    myLayer.onblur = function() {     
        myLayer.style.display = 'none'; 
    }; 

    if (myLayer.style.display == "none" || myLayer.style.display == "") {   
        myLayer.style.display = "block";   
    } else {   
        myLayer.style.display = "none";   
    }   
}

</script>
</head>

<body>
<div class="info">   
     Some Text Boom A <a  onclick="menu('id1');">Link</a> | More text  
     <a onclick="menu('id2');">Another Link</a> | more text  
     <ul id="id1" class="submenu">   
       <li><a href="dfhdfh">A1</a></li>   
       <li><a href="aetjetjsd">A2 This is Long</a></li>   
       <li><a href="etetueb">A3</a></li>   
     </ul>   
    <ul id="id2" class="submenu">   
       <li><a href="dfhdfh">B1</a></li>   
       <li><a href="aetjetjsd">B2</a></li>   
       <li><a href="etetueb">B3</a></li>   
     </ul>   
  </div>  
</body>
</html>
A: 

jQuery creates a blur event you can bind a function to, is there a strong reason not to use jQuery? Using a JavaScript library even if it is just for event handling, helps insulate you from browser differences. I've only ever used focus/blur events for text input or textarea elements in a form. It sounds like you want a list to float on top of the other elements. I'd position the list relatively and give it a z-index that is higher than the background. I'd bind a click event to the area outside the list, to dismiss the list pop-up. Is toggling a pop-up/modal window what you want? I'd have a look at jQuery SimpleModal for modal window examples, or look at how one is implemented if you want to roll your own.

Andy Atkinson
I already have the dropdown menu working. I don't know how to bind a click event to the area outside the list; that is my question. I don't want to use jQuery because I don't know anything about jQuery. I'm just trying to learn Javascript, then I'll take a stab at jQuery.
Jim Roboju
Add a click handler to the area outside your dropdown, this might be the body element. Then position your dropdown on top of the other elements using the z-index property. Now clicks outside the dropdown can fire an event handler to close the dropdown. Clicks on the dropdown will not trigger the "close dropdown" function.
Andy Atkinson
+1  A: 

This is quite simple actually.

Once you have a reference to the DOM element that you want to bind the blur event listener to, assign it like this:

myLayer.onblur = function() {
    myLayer.style.display = 'none';
};
Jacob Relkin
So I just updated the post to include the javascript that I'm currently using. Where do I put your code. Do I put it after this line? `var myLayer = document.getElementById(id);` ?
Jim Roboju
I know I can just add the onblur="" event to the html, but it seems as though you are suggesting a way in which the onblur() event does not need to be made explicity, but rather it is somehow binded to the id through javascript.
Jim Roboju
@Jim, In response to your first comment, yes, `element` would be `myLayer` in my code. Binding the event in JavaScript is a lot better than doing it in HTML.
Jacob Relkin
Thanks. Where do I put your code. I tried it just after the line i referenced and it didn't work.
Jim Roboju
Let me see your `getElementById` code.
Jacob Relkin
I've edited and attached the complete code. I left out some css stuff and simplified the javascript for the example. It still doesn't work however.
Jim Roboju
myLayer.onblur will do what you suggest, but be careful of memory leaks; using this structure inside your menu function will cause a problem. You should instead make the onblur a distinct function. See http://blog.j15r.com/2005/01/dhtml-leaks-like-sieve.html, specifically the section on closures.
jvenema
If you take the code in the second edit and put it in an html page all by itself, it doesn't work. When you click off to the right of the visible ul it just sits there, it should dissapear.
Jim Roboju
A: 

If you are looking for a way to stop "onclick" event if it happens inside your menu then "event.stopPropagation();" may be what you need

<body onclick="menu('id1'); menu('id2');">
  <div class="info">  
     Some Text Boom A <a  onclick="menu('id1');">Link</a> | More text 
     <a onclick="menu('id2');">Another Link</a> | more text 

     <ul id="id1" class="submenu" onclick="alert('click menu'); event.stopPropagation();">  
       <li><a href="dfhdfh">A1</a></li>  
       <li><a href="aetjetjsd">A2 This is Long</a></li>  
       <li><a href="etetueb">A3</a></li>  
     </ul>  
    <ul id="id2" class="submenu" onclick="alert('click menu'); event.stopPropagation();">  
       <li><a href="dfhdfh">B1</a></li>  
       <li><a href="aetjetjsd">B2</a></li>  
       <li><a href="etetueb">B3</a></li>  
     </ul>  
  </div> 
</body>
iKid
Propagation is not an issue. But thanks for the response. I know its there now in case it ever happens.
Jim Roboju
@Jim Roboju You can use this to archive what you want above. For example. you put menu(id) in the onclick() event of the body then stop propagation in the onlick() of the menu ==> the menu(id) would never be called. just try to run the code above you will see.
iKid
It kinda solves the problem, but a new one arise. It will set the uls to hidden if they are visible, but it will make this visible if they are hidden. I feel like the problem could be solved this way, but it would take like a state variable that would have to be stored in a closure or something when its called by the body tag. I feel like there is a better way. I'll look into this solution if I don't find one. Thanks for the follow up too.
Jim Roboju
no problem, but just don't use my code directly haha that's lousy one.. you can fix the flipping by simply define a new function, let say hidemenu(id) that only hide the menu (not like your current menu() flip the thing) and put that in the body onclick()
iKid
Yeah, i realized that righ after I commented. Is there anything wrong with having a ton of onblur() calls within the body tag?
Jim Roboju
not sure how do you want to put onblur(). but if you have a bunch of function calls, define a new function and put all that inside.
iKid
Thanks for your help, I'm done for the night.
Jim Roboju