Reputation: 1286
So there is a left side vertical menu. And it has a small options button. When clicked, it should open a div which will have various filter options. Now, i need it to appear when clicked, and disappear when either the options button is clicked again, or the user clicks anywhere outside the div.
So i have the following code.
//options filter menu animation
$('#optionsmenu').hide(); //hides the menu
$('.optionsfilters').click(function(e){
var $this = $('#optionsmenu');
$this.show();
var left = $('#sidebar').css('width'),
top = $(this).offset().top;
$this.css('top', top);
$this.css('left', left);
});
$(':not(.optionsfilters)').click(function(e){
$('#optionsmenu').hide();
});
The HTML is
<div id="sidebartitle">
<h2>Organisation</h2>
<a id="optionsfilters" class="optionsfilters">Options</a>
</div>
<div id="optionsmenu" class="optionsfilters">
<h3>Add New</h3>
<ul>
<label>Year</label>
<select>
<option>2000</option>
<option>2001</option>
<option>2002</option>
<option>2003</option>
<option>2004</option>
<option>2005</option>
</select>
</ul>
</div>
Its not working together, i.e. the two javascript functions, the first one works alone, when the second one is commented out. The second one works, if i comment out the hide part, and add an alert message. But together, they don't work.
Whats the conflict?
Upvotes: 2
Views: 123
Reputation: 1100
Ok there are a few things you will want to do:
1) If you want the original button to close the menu you will want to use .toggle()
rather than .show()
2) You will want to detect a click on the document, to hide the options menu. Which will not be called if it is the options menu that is clicked due to the e.stopPropagation();
(point 4 below).
$(document).click(function() {
$('#optionsmenu').hide();
});
3) You also want to check (as both have the same class) that the .optionsfilters
that was clicked was not the filters themselves (otherwise this will stop you clicking an option).
if( e.target !== this ) {
return;
}
4) Use e.stopPropagation();
to stop the event bubbling up to the parents (or document).
This should be what you are looking for:
$('#optionsmenu').hide(); //hides the menu
$('.optionsfilters').click(function(e){
e.stopPropagation();
if( e.target !== this ) {
return;
}
var $this = $('#optionsmenu');
$this.toggle();
var left = $('#sidebar').css('width'),
top = $(this).offset().top;
$this.css('top', top);
$this.css('left', left);
});
$(document).click(function() {
$('#optionsmenu').hide();
});
Here is the working fiddle: http://jsfiddle.net/lee_gladding/pny4vq26/
Upvotes: 2
Reputation: 10994
The problem is mainly that both your click handlers run and one shows the menu then the other one hides it.
Why? Because that's not a good selector. Until you reach the element with the class .optionsfilters your click goes through body, #sidebartitle and then it reaches the element a. And since the parents of that element don't have the class .optionsfilters, it will hide the menu.
So I changed the code a little. First of all don't use the class as a click handler. Use the IDs
$('#optionsfilters').click(function (e) { // ID of options
var $this = $('#optionsmenu');
$this.toggle(); // toggle show/hide when click on it
var left = $('#sidebar').css('width'),
top = $(this).offset().top;
$this.css('top', top);
$this.css('left', left);
});
The you need to check when you click outside of the #optionsmenu. For that you attach a click handler on document and check the e.target
$(document).click(function (e) {
if (!$(e.target).closest('.optionsfilters').length)
$('#optionsmenu').hide();
});
If the e.target itself is not .optionsfilters and is not a child of a parent with that class then you hide the menu.
Working example below.
//options filter menu animation
$('#optionsmenu').hide(); //hides the menu
$('#optionsfilters').click(function (e) {
var $this = $('#optionsmenu');
$this.toggle();
var left = $('#sidebar').css('width'),
top = $(this).offset().top;
$this.css('top', top);
$this.css('left', left);
});
$(document).click(function (e) {
if (!$(e.target).closest('.optionsfilters').length) $('#optionsmenu').hide();
});
#optionsmenu{
background:lightblue;
}
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="sidebartitle">
<h2>Organisation</h2>
<a id="optionsfilters" class="optionsfilters">Options</a>
</div>
<div id="optionsmenu" class="optionsfilters">
<h3>Add New</h3>
<ul>
<label>Year</label>
<select>
<option>2000</option>
<option>2001</option>
<option>2002</option>
<option>2003</option>
<option>2004</option>
<option>2005</option>
</select>
</ul>
</div>
Upvotes: 1
Reputation: 45
I can't understand, but if your menu is hide (first instruction in your js), how can you click on it for show it?
EDIT: Didn't noticed the class attriute on previous div. My fault.
Upvotes: -1
Reputation: 6914
a classic demonstration of stopPropagation in jQuery (http://api.jquery.com/event.stoppropagation/)
here is a fiddle that simplify this: http://jsfiddle.net/ymzrocks/98082xk7/1/
in short:
$('.optionsfilters').click(function(e)
{
e.stopPropagation(); // or elese it will fire the parent event
var $this = $('#optionsmenu');
$this.show();
var left = $('#sidebar').css('width'),
top = $(this).offset().top;
$this.css('top', top);
$this.css('left', left);
});
Upvotes: 1
Reputation: 533
Here you go
//options filter menu animation
var filters = $('.optionsfilters');
var options = $('#optionsmenu');
options.hide(); //hides the menu
filters.click(function(e){
$('#optionsmenu').toggle();
var left = $('#sidebar').css('width'),
top = $(this).offset().top;
_this.css('top', top);
_this.css('left', left);
});
$(document).click(function(e) {
if (!filters.is(e.target) && filters.has(e.target).length === 0) {
options.hide();
}
});
Upvotes: 1
Reputation: 569
Be careful using :not for any other elements, because if - for example - you click the dropdown, the sidebar hides again, which I doubt you want to happen.
It'd be better to define areas you want to make the sidebar hide when clicked, like the main content area.
Also since you use the class .optionsfilters
on your sidebar menu, when you click in there the sidebar will hide again.
Try this JS Fiddle.
Upvotes: 0