JavaScript Onclick Dropdown Menu not working - javascript

I am trying to make an onclick dropdown menu for a website. I want my .sublink elements to slide down when I click on the .dropdown element and then for the .sublink to slide back up when I click on anywhere else on the page.
The menu drops down, but it does not slide back up when I click somewhere else on the website.
Following is the code that I currently have for the menu. Can someone please help me on this? Thank you!
$(function() {
$('.dropdown').click(function() {
$('.sublinks').stop(false, true).hide();
var submenu = $(this).parent().next();
submenu.css({
position: 'absolute',
top: $(this).offset().top + $(this).height() + 'px',
left: $(this).offset().left + 'px',
zIndex: 1000
});
submenu.stop().slideDown(300);
//click anywhere outside the menu
$(document).click(function() {
var $el = $(this);
$el.not('.dropdown') && $el.slideUp(300);
});
});
});

Try to use blur event:
$('.dropdown').blur(function () {
var $submenu = (...); // <- get submenu selector here
$submenu.slideUp();
});

In your code, which is for click anywhere in document, this will point to a document, not to an actual element where event happened. You can modify your code like below (use e.target instead of this):
$(function() {
$('.dropdown').click(function() {
$('.sublinks').stop(false, true).hide();
var submenu = $(this).parent().next();
submenu.css({
position: 'absolute',
top: $(this).offset().top + $(this).height() + 'px',
left: $(this).offset().left + 'px',
zIndex: 1000
});
submenu.stop().slideDown(300);
});
//click anywhere outside the menu
$(document).click(function(e) {
var $el = $(e.target);
if(!$el.hasClass('.dropdown') && $el.closest(".dropdown").length == 0 && !$el.hasClass('.sublinks') && $el.closest(".sublinks").length == 0)
$('.sublinks:visible').slideUp(300);
});
});
See also $el.closest(".dropdown").length == 0 it is to ensure that click happens not in child element of .dropdown
Here is a demo for it. Click in different locations and check console: http://jsfiddle.net/2ryWF/. You will find that this always points to document

Looks like your hook for click anywhere is inside the dropdown click hook,
try something like this(not tested);
$(function() {
//click on menu(dropdown div)
$('.dropdown').click(function() {
$('.sublinks').stop(false, true).hide();
var submenu = $(this).parent().next();
submenu.css({
position: 'absolute',
top: $(this).offset().top + $(this).height() + 'px',
left: $(this).offset().left + 'px',
zIndex: 1000
});
submenu.stop().slideDown(300);
});
//click anywhere in document
$(document).click(function() {
var $el = $(this);
$el.not('.dropdown') && $el.slideUp(300);
});
});

Related

Script only works properly on page refresh

I have a function that makes a side panel (.link-panel) stop when it reaches (.footer), inside (.link-panel) is (.cover). (.cover) is the div that contains all the elements of the (.link-panel) so it is fixed and technically it is the one that stops when it reaches the (.footer). My function first initializes if .control_panel is at position: inline-block. If it isn't (meaning it's display: block and the page width is <= 750px), then an else statement initializes and makes .cover's position relative.
This function is working properly only on page refresh. For example, let's say my page's size is at: 1300px. The display works correctly, but when I shrink the window size to below <= 750px, the side-menu stays fixed even if I change the css property using jQuery. The problem can only be solved if I refresh the page. Then if I start at <= 750px and resize back up, the side menu does not display correctly and I have to refresh the page again for it to display correctly.
My code
$(document).ready(function(){
var panel = $(".control_panel").css("display");
if(panel == "inline-block"){
fixedScrollBar();
}else{
$(".link-panel").css("position", "relative");
}
});
function fixedScrollBar(){
var windw = this;
$.fn.followTo = function ( elem ) {
var $this = this,
$window = $(windw),
$bumper = $(elem),
bumperPos = $bumper.offset().top + -40,
thisHeight = $this.outerHeight(),
setPosition = function(){
if ($window.scrollTop() > (bumperPos - thisHeight)) {
$this.css({
position: 'absolute',
top: (bumperPos - thisHeight)
});
} else {
$this.css({
position: 'fixed',
top: 60
});
}
};
$window.resize(function()
{
thisHeight = $this.outerHeight();
setPosition();
});
$window.scroll(setPosition);
setPosition();
};
$('.cover').followTo('.footer');
}
Wrap your code in a resize event, test in your scroll event if the panel is inline-block and disable the css functions if its not:
$(document).ready(function() {
$(window).resize(function() {
var panel = $(".control_panel").css("display");
if (panel == "inline-block") {
fixedScrollBar();
} else {
$(".cover").css({"position":"relative","top":0});
}
}).trigger('resize');
});
function fixedScrollBar() {
var windw = this;
$.fn.followTo = function(elem) {
var $this = this,
$window = $(windw),
$bumper = $(elem),
bumperPos = $bumper.offset().top + -40,
thisHeight = $this.outerHeight(),
setPosition = function() {
if($(".control_panel").css("display") == "inline-block") {
if ($window.scrollTop() > (bumperPos - thisHeight)) {
$this.css({
position: 'absolute',
top: (bumperPos - thisHeight)
});
} else {
$this.css({
position: 'fixed',
top: 60
});
}
};
}
$window.scroll(setPosition);
setPosition();
};
$('.cover').followTo('.footer');
}
https://jsfiddle.net/e9dcmL2q/4/

Anchor doesn't work

I have a problem with link inside page. This is part of jQuery code I use in my page
$.fn.stopAtTop= function () {
var $this = this,
$window = $(window),
thisPos = $this.offset().top,
//thisPreservedTop = $this.css("top"),
setPosition,
under,
over;
under = function(){
if ($window.scrollTop() < thisPos) {
$this.css({
position: 'absolute',
top: ""
});
setPosition = over;
}
};
over = function(){
if (!($window.scrollTop() < thisPos)){
$this.css({
position: 'fixed',
top: 0
});
setPosition = under;
}
};
setPosition = over;
$window.resize(function()
{
bumperPos = pos.offset().top;
thisHeight = $this.outerHeight();
setPosition();
});
$window.scroll(function(){setPosition();});
setPosition();
};
And this is a example DEMO
When I scroll down everything works fine but when I want go to the top of the page it's impossible. I know that issue is that the script makes the div fixed, but I don't know how to fix it. Any ideas?
Add a click handler that scrolls to the top of the page:
$("[href='#one']").click(function() {
scrollTo(0, 0);
});
jsfiddle.net/jx8nmhfq/1

Div apperas on second hover

I'm working on custom tooltip that ollows cursor, but it's only firing on second hover. I searched stack from floor to ceiling and all those advices i tried wasn't very helpful. I made code as simple as possible, but stil all works on second hover. I'm out of ideas.
Here is the code
$(".bar").bind('mouseover',handler);
$(".bar").bind('mousemove', function(e){
$('.tail').css({
left: e.pageX + 20,
top: e.pageY
});
});
function handler(ev) {
var target = $(ev.target);
var elId = target.attr('id');
if( target.is(".bar") ) {
$('#'+elId).hover(function() {
$('#tail'+elId).show();
}, function() {
$('#tail'+elId).hide();
});
}
}
And here goes the fiddle
http://jsfiddle.net/hj57k/3070/
Thanks or help.
EDIT
Whoa guys, that was really fast! All your solutions worked. +1 for everyone. But solution from MrUpsidown is most elegant... Thanks to all. :)
You could maybe do something easier:
$(".bar").bind('mouseenter', function () {
$('#tail' + $(this).attr('id')).show();
});
$(".bar").bind('mouseleave', function () {
$('#tail' + $(this).attr('id')).hide();
});
$(".bar").bind('mousemove', function (e) {
$('#tail' + $(this).attr('id')).css({
left: e.pageX + 20,
top: e.pageY
});
});
JSFiddle demo
Because you are attaching the hover event when mouseover. You should attach the hover event at the beginning, like this:
$(".bar").each(function(index,elem){
var target = $(elem);
var elId = target.attr('id');
if( target.is(".bar") ) {
$('#'+elId).hover(function() {
$('#tail'+elId).show();
}, function() {
$('#tail'+elId).hide();
});
$('#'+elId).bind('mousemove', function(e){
$('#tail'+elId).css({
left: e.pageX + 20,
top: e.pageY
});
});
}
});
It's because you init the hover function only when JS bind the mouseover.
You have to directly use hover method.
Have a good day !
I think your problem here is that the first hover yo do only binds the element to the function. I slightly modified your script, automatically running .show() and conditioning .hide() to a mouseout event. Like this:
function handler(ev) {
var target = $(ev.target);
var elId = target.attr('id');
if( target.is(".bar") ) {
$('#tail'+elId).show();
$('#'+elId).mouseout(function() {
$('#tail'+elId).hide();
});
$('#'+elId).bind('mousemove', function(e){
$('#tail'+elId).css({
left: e.pageX + 20,
top: e.pageY
});
});
}
}
You can see it here http://jsfiddle.net/cc7s9rcf/
I hope it helped.
Try this update
$(".bar").bind('mouseover',handler);
/*
$('.bar').hover(function() {
$('.tail').show();
}, function() {
$('.tail').hide();
});
*/
function handler(ev) {
console.dir(ev);
var target = $(ev.target);
var elId = target.attr('id');
if( target.is(".bar") ) {
console.dir(ev.type);
if (ev.type === 'mouseover') {
$('#tail'+elId).show();
} else {
$('#tail'+elId).hide();
}
/*
$('#'+elId).hover(function() {
$('#tail'+elId).show();
}, function() {
$('#tail'+elId).hide();
});*/
$('#'+elId).bind('mousemove', function(e){
$('#tail'+elId).css({
left: e.pageX + 20,
top: e.pageY
});
});
}
}
https://jsfiddle.net/hj57k/3276/
I just added display:block in this javascript
$('#'+elId).bind('mousemove', function(e){
$('#tail'+elId).css({
left: e.pageX + 20,
top: e.pageY,
display:'block'
});
});
http://jsfiddle.net/hj57k/3273/

Div wont stop scrolling with Page

Using my code at:
http://jsfiddle.net/Pd7nm/
I want the sidebar to stop scrolling with the page at a certain point but it just keeps on going. I have tried multiple things and its not working.
This is the Javascript Method thingy
var windw = this;
$.fn.followTo = function ( pos ) {
var $this = this,
$window = $(windw);
$window.scroll(function(e){
if ($window.scrollTop() > pos) {
$this.css({
position: 'absolute',
top: pos
});
} else {
$this.css({
position: 'fixed',
top: 0
});
}
});
};
$('#side').followTo(250);
Updated JQuery Fiddle is here
$(window).scroll(function() {
var height = $(window).scrollTop();
if(height>250){
$(".sidebar").css({"position":"fixed","top":0});
}
});
See This demos I have removed in "br" tag
Demos - jsfiddle.net/Nu3eu/1/

jQuery append (or appendTo) with Animation

I have a UL-LI e.g.
<ul>
<li id="1">item-1</li>
<li id="2">item-2</li>
<li id="3">item-3</li>
<li id="4">item-4</li>
</ul>
I would like to move one of the items to another position in the list. e.g. item-2 to AFTER item-4.
Normally I can do this by deleting the item and then appending it after another.
But I would like to do this to happen visually with animation. As in, item-2 descends to after item-4.
How can I achieve this?
IDs should not start with numbers...
$('#two').slideUp(500, function () {
$('#four').after(this);
$(this).slideDown(500);
});
Here is a demo: http://jsfiddle.net/jasper/8JFBA/
Or if you always want to add the element to the end:
$('#two').slideUp(500, function () {
$('ul').append(this);
$(this).slideDown(500);
});
Here is a demo: http://jsfiddle.net/jasper/8JFBA/1/
Update
Ok, so if you want the element to slide to it's new location here ya go:
//absolutely position the element and give it a top property so it doesn't go to the top of the container
$('#two').css({ position : 'absolute', top : $('#two').position().top });
//now get the offset to the bottom of the list by getting the top offset and height for the last list-item
var lastOffset = ($(this).children().last().position().top + $(this).children().last().height());
//now animate the element to the new position
$('#two').animate({ top : lastOffset }, 1000, function () {
//when the animation is done, re-add the element to the new position in the list and reset it's position and top values
$(this).appendTo('ul').css({ position : 'relative', top : 0 });
});
And a demo: http://jsfiddle.net/jasper/8JFBA/3/
Update
You can animate not only the element being moved to the end of the list but you can animate the rest of the list items as they move up:
var $LIs = $('ul').children(),
liHeight = 20;
$LIs.on('click', function () {
var index = ($(this).index()),
$LIsAfter = $LIs.filter(':gt(' + index + ')');
console.log(index);
$(this).css({ position : 'absolute', top : $(this).position().top });
$.each($LIsAfter, function (i) {
$(this).css({ position : 'absolute', top : ((i + index + 1) * liHeight) });
});
$(this).stop(true, true).animate({ top : (($LIs.length - 1) * liHeight)}, 1000, function () {
$(this).appendTo('ul').css({ position : 'relative', top : 0 });
});
$.each($LIsAfter, function (i) {
$(this).stop(true, true).animate({ top : ((index + i) * liHeight) }, 1000, function () {
$(this).css({ position : 'relative', top : 0 });
});
});
});
Here is a demo: http://jsfiddle.net/jasper/8JFBA/8/
This isn't quite complete, there is still a bug or two, but it should help get anyone started on the idea.
I tried to implement a smoother transition when you descend and below is my version..
You need to try out the demo to understand how it works.. Select value from the drop down and hit Descend to see the animation.
DEMO
Edit: Updated top position of $from before addClass('active') to start from the exact position and not top: 0px. Thanks to Jasper for finding this issue.
var $from = $('#from');
var $to = $('#to');
$('button').click (function () {
var from = $from.val();
var to = $to.val();
var $li = $('ul li');
var $fromEl = $('#' + from);
var $toEl = $('#' + to);
//only descending
if (from == to || $li.index($fromEl) > $li.index($toEl)) return;
var destX = $toEl.position().top;
$toEl.after('<li id="tmpLi2"></li>');
$('#tmpLi2').animate({height: $fromEl.outerHeight()}, 1000);
//add a blank li for smooth animation
$fromEl
.after('<li id="tmpLi1"> </li>')
.css ('top', $fromEl.position().top)
.addClass ('active' )
.animate({
top: (destX)
},
1000,
function() {
$toEl.after(this);
$('#tmpLi2').remove();
$(this).removeClass('active');
});
$('#tmpLi1').slideUp(function() { $(this).remove()});
});

Categories

Resources