Button that displays and hides a sliding menu - javascript

I'm trying to build a header with a menu button that triggers a sliding menu. I can make the menu appear when I press the button, but I also want it to dissappear when I click the button again.
This is the event that triggers when the button is clicked.
$('#nav-button').click(function () {
$("#slidermenu").animate({right: "0px"}, 200);
$("body").animate({right: "300px"}, 200);
});
I looked up the animate method and saw that it has a function called done, which takes two parameters. A promise and a boolean. So I figured I can use a if-statement to check if the animation is done, and if the animation is done, the button would send the slidermenu back.
But how can I test if animate().done() is true? Or is there a more simple way of achiveing this?
Here is my fiddle.

.is(':animated') will return true if it's currently being animated.
In the context of what you're trying to do:
if(!$('#slidermenu').is(':animated'))
{
// Animation has finished
}
As an aside:
I try and do this with CSS only now where possible. If you use jQuery toggleClass and predefine the right attributes in your CSS for the toggled classes, you can add a CSS transition to deal with the animation. Just thought it was worth mentioning (this does come with it's own compatibility issues).

Like DeeMac said, it may be better to do this with css transition instead of jQuery animate. But just to add an option, I'll try to show you how to get this to work with jQuery animation also.
First of all, instead of inspecting if the animation is still running or not, you can just stop the ongoing animation before starting another. It will make the button to respond immediately to the users clicks.
For finding out if the menu is open or not, you can use toggleClass. This way you can just use hasClass to determine in which direction you need to animate the menu.
So, this what I came up with:
$('#nav-button').click(function () {
$("#slidermenu").stop();
animateToPosition = "0px";
if ($("#slidermenu").hasClass("open")) {
animateToPosition = "-300px";
}
$("#slidermenu").toggleClass("open");
$("#slidermenu").animate({
right: animateToPosition
}, 200);
});
I made a Demo. If you are going with the css solution, it's fine. Maybe this will help someone else in the future.

Related

How to execute code after 3rd party slide down animation?

Background:
I am using the materialize JS to create collapsible divs. When a div that has a class of collapsible-header is clicked, a slide down animation occurs on the sibling div that has a class of collapsible-body, showing the contents of the collapsible-body.
What I am trying to accomplish is when a collapsible header is clicked, the browser should scroll to the top of that div so that the contents are in full view of the user. I have used an on click event, which works fine on the first collapsible. But then, if you have an open collapsible and you click on another to open it, it doesn't scroll to the top of the clicked div properly (it will scroll to the middle of the body, or way above the top of the div).
JS Fiddle of on click functionality: https://jsfiddle.net/f83dct8f/4/
I am able to accomplish what I am looking to do by editing the Materialize JS itself. Here is how the line looks before my edit:
object.siblings('.collapsible-body').stop(true, false).slideDown({
duration: 350,
easing: "easeOutQuart",
queue: false,
complete: function() {
$(this).css('height', '');
}
});
I add the following to the complete portion of the above statement to accomplish what I'm looking for:
$('body').animate({scrollTop: $('.collapsible-header.active').offset().top },'slow');
Question: I do not want to edit the Materialize 3rd party code to accomplish what I need, so I need to find a way to implement the body animate code after the slide down is finished, without editing the Materialize animation. I know there has to be a way to do it?
I have tried event queues on the collapsible body, which seemed promising, but my test console print executed during the animation. See below. If someone could point me in the right direction of what else I could try, I would greatly appreciate it.
$('.collapsible-header.active')
.siblings('.collapsible-body').slideDown().queue(function(){
console.log('DONE');
});
You should be able to use the onOpen option when initialising your .collapsible. Pass in a function to execute when the accordion is opened. The function receives the element as a argument.
$(document).ready(function() {
$('.collapsible').collapsible({
onOpen: function(el) {
$('body').animate({scrollTop: el.offset().top },'slow');
}
});
});

How can I keep mega sub menu open after mouse leaves top navigation button?

I am new to jQuery. I am trying to set up a mega drop down that is 100% width on the screen but the content is centered. Also the top navigation buttons are centered.
How can I keep the sub content area open after the mouse leaves the top button?
Here is the fiddle: http://jsfiddle.net/uf1107qs/
$('.top1').on('mouseenter', function () {
$('.sub1').slideDown(200).addClass('.abTop');
$('.fades1').delay(50).fadeIn(200);
});
$('.top1').on('mouseleave', function () {
$('.sub1').delay(600).slideUp(200).removeClass('.abTop');
$('.fades1').fadeOut(0);
});
did you want the .subX and .fades1 keep showing and never closed?
perhaps this is this what you want?
JSFIDDLE
Edit :
sorry for my misunderstanding before. You can achieve that by using setTimeout rather than delay, here's the result : JSFIDDLE, it's still ugly though, because there are many repeated code inside it.
Basically you need to setTimeout when mouseleave the top, and clearTimeout when mouseenter the top or sub
Other Way :
the other way around to achieve it, you can use only CSS by using CSS property like position, visibilty, opacity, z-index like in this example on JSFIDDLE
Instead of using delay, or a timeout.. you can use what's called a callback function, which is supported by most jQuery built-in functions. This is your code:
$('.top1').on('mouseenter', function () {
$('.sub1').slideDown(200).addClass('.abTop');
$('.fades1').delay(50).fadeIn(200);
});
Here is my version using the concept of a "callback":
$('.top1').on('mouseenter', function () {
//see the difference?
$('.sub1').slideDown(200, function(){
$('.fades1').fadeIn(200);
}).addClass('.abTop');
});
Essentially what is happening, is that slideDown() is able to accept an optional parameter that is function. This function will then get triggered only AFTER 200ms have passed (Since you have it set to slideDown(200)).
So callback function in this case, is simple a function that is called, only after the parent function (for simplicity sake) is done doing what it's supposed to do. For more info:
http://www.w3schools.com/jquery/jquery_callback.asp
ALSO
Since you are new to jQuery, you should definitely check out the hover() function. You will be able to simplify your code by probably half the amount of JS lines, and be much more readable!
http://api.jquery.com/hover/

Reverse onClick Event

I am a genuine javascript novice and looking some pointers in my learning - not homework nor is it anything commercial.
I have a function here which shows an element which is hidden due to the first 2 lines of the function. I start by clicking the heading and the 2 hidden divs appear, which is exactly what I wanted to happen. However, now when I use this second function, it won't return to it's windown onload state. Why is this? Is there a better way to achieve this?
1st Function
$(window).ready(function(){
$('.miniC').css("display", "none");
$('.miniI').css("display", "none");
$(".heading").click(function(){
$('.miniC').slideDown();
$('.miniI').slideDown();
$('.miniC').show();
$('.miniI').show();
});
});
2nd Function (Reverse)
$(window).ready(function(){
$(".hideOut").click(function(){
$('.miniC').slideUp();
$('.miniI').slideUp();
$('.miniC').hide();
$('.miniI').hide();
});
});
Thanks in advance and any reference to good reading material is appreciated.
* Corrected Missing closing quote - this was a mistake of me typing it into Stack Overflow - Sorry! *
It seems like you want to toggle the visibility of an element, and since you're already sliding it, why not just use slideToggle:
$(".miniC").css("display", "none");
$(".miniI").css("display", "none");
$(".heading").click(function () {
$(".miniC").slideToggle();
$(".miniI").slideToggle();
});
Example
You shouldn't need to call .hide() and .show() - they will be dealt with as part of the slide functions. However, you're calling them immediately after the slide, but that takes a while to complete (400ms by default) meaning that .hide() fires before .slideUp() completes.
Outside the question scope, but still applicable.
$('.miniC').css("display", "none");
$('.miniI').css("display", "none");
This part of the page functionality should probably in CSS, which will result in the browser rendering the initial paint of the page correctly. In your case the browser paints the "miniC" and "miniI" elements, then your jQuery code updates the CSS display property to "none" for both individually. Triggering two additional repaints of the page. So, basically with the jQuery code you are drawing the page three times for an effect that could achieved with a single paint.
Then like Charlie said add a listener for the click.
$(".heading").click(function () {
$(".miniC").slideToggle();
$(".miniI").slideToggle();
});
Because slideUp() and hide() are written inside the click event. So, it wont fire on window ready, but only onclick of $(".hideOut").
There is a typo in your first function.
a single quote is missing in the line:
$('.miniC).show();

check for ('div')mouseenter on ('a')mouseleave

my problem is following:
I got a trigger(a) and a popup(div). The div doesn't lie nested inside the anchor.
When I hover over a, I want the div to show up.
When I go from a to the div, I want it to stay visible.
When I leave the div, I want it to close.
When I hover over a and leave without entering the div, I want the div to close.
I got most of that figured out, but now I'm struggeling with requierement no. 2.
When checking for mouseleave on a, I check if there is a mouseenter on the div. If it is, I want to abort the mouseleave. If not, I want to close the div.
What am I doing wrong? Is this even the right way to do this?
Here's the markup:
<a href="#" class="popup_toggle" style='display:block;width:50px;height:50px;border:1px solid red;position:relative;'>Toggle</a>
<div class="popup_div" style='position:absolute;top:50px;left:0px;border:1px solid blue;display:none;'>Popup</div>
Here's the jQuery:
$('.popup_toggle').mouseenter(function() {
var element = $(this).next('.popup_div');
$.data(this, 'timer', setTimeout(function() {
element.show(100);
}, 500));
});
$('.popup_toggle').mouseleave(function() {
clearTimeout($.data(this, 'timer'));
if($('.popup_div').mouseenter==true)
{
return false;
}
else
{
$('.popup_div').hide(100)
};
});
What you're trying to do is fairly simple. When entering the trigger, identify the panel (layer, popup, whatever), save reference to each other using .data() and have the event handlers check if the related targets are either the trigger (from the panel view) or the panel (from the trigger view). I threw something together. Have a look at the console log to see how this works… http://jsfiddle.net/rodneyrehm/X5uRD/
That will most likely not work...no. I would suggest that you add a mouseenter and mouseleave callback to you <div> element as well and have them set a global variable that tells your other callbacks how to handle their events, i.e. "if global variable is true, don't hide the popup on mouseleave, otherwise hide popup" or something like this.
The other approach would be to check whether the mouse is inside the popup when the mouseleave callback tries to hide the popup. That might be much more work than it is worth though.
I believe the problem with your implementation is that the mouseenter on the div will fire shortly after the mouseleave from the a.
This would give you something like:
$('.popup_toggle').mouseenter(function() {
// Clear any pending "hide" timer
// Set a show timer
});
$('.popup_toggle').mouseleave(function() {
// Clear any pending "show" timer
// Set a hide timer
});
$('.popup_div').mouseenter(function() {
// Clear any pending "hide" timer
});
Note that you'll have to make sure that you access the same timer from both the .popup_toggle event and the .popup_div event. You may want to consider using Ben Alman's doTimeout plugin to help with this. It (usually) results in much clearer code than manually working with setTimeout/clearTimeout.

Help needed with showing and hiding a div

I'm having a problem with an image viewer I'm creating. Like the image below, the 'window' is where the image is shown and 'paging' is where the user can change the image. I've used this Jquery script to make the 'paging' fade in whenever the window is hovered over - It's hidden to start with. Although when the user hovers onto 'paging', it flickers. (Like shows then hides, etc.)
I suppose it's because the mouse isn't hovering over the 'window' anymore. Can anyone suggest how I can make 'paging' remain showing? Thanks for the help! :)
$(".window").hover(function() {
$(".paging").fadeIn('fast');
}, function() {
$(".paging").fadeOut('fast');
});
You can use .stop() here and include both in your .hover() selector, like this:
$(".window, .paging").hover(function() {
$(".paging").stop(true, true).fadeIn('fast');
}, function() {
$(".paging").stop(true, true).fadeOut('fast');
});
This way, when you leave to enter the child or back to the parent it stops the fade out and brings it right back, resulting in no visible action to the user.
You could try using mouseover and mouseout instead. I'm not sure that mouseout would react the same way hover does.
In fact, when you pass your mouse over the paging there is a magical thing that happens which is called "event bubbling": the "hover" event is passed to the container which is the parent of the "hovered" object, and so on until the "document" object.
So to solve your problem, you need to stop bubling, you can do it with "return false":
$(".paging").hover(function() {
return false;
}, function() {
return false;
});
(It's possible that in recent version of jquery you can replace the argument function(){return false;} by just false.)

Categories

Resources