Jquery css(width, 0) not working if the element is hidden - javascript

I have created a quick jsfiddle here showing it not working.
The problem I have is with the slide up. I want it to work so that it only sets the width to 0 after the slideup has finished. The obvious callback function does not seem to be getting called after the slideup has finished.
I would like it to work like this:
Shows the red box by sliding down and increasing the width together.
Click again and the box slides up then sets the width the 0. So that if the user clicks the button again the first animation would appear the same.
var $foo = $("#elm");
$("#btn").toggle(function() {
showDropDown();
}, function() {
hideDropDown();
});
function showDropDown(){
$foo.slideDown({duration:500, queue:false}).animate({"width": 400}, 250);
}
function hideDropDown(){
$foo.slideUp({duration:800, queue:false},function(){
$foo.css({"width": 0});
});
}
UPDATE:
The strange thing is that if I add a alert() into the callback function for slidedown it never gets called.

Edit: Sorry for the first answer, didn't pay attention.
The problem is that the callback is not executed, because you don't give the parameters according to the API, and the callback is not "wired" in.
Instead, you can use the promise().done(...) combination to achieve the objective you wanted.
So, you should modify your hideDropDown method as follows:
function hideDropDown(){
$foo.slideUp({duration:800, queue:false}).promise().done(function(){
$foo.css("width", "0px");
});
}
From the jQuery docs:
"The .promise() method returns a dynamically generated Promise that is resolved once all actions of a certain type bound to the collection, queued or not, have ended."

Maybe you just need to use animate to reset width to 0 like this:
var $foo = $("#elm");
$("#btn").toggle(function() {
showDropDown();
}, function() {
hideDropDown();
});
function showDropDown(){
$foo.slideDown({duration:500, queue:false}).animate({"width": 400}, 250);
}
function hideDropDown(){
$foo.slideUp({duration:800, queue:false}).animate({"width": 0}, 1);
}
or set width to 0 like this:
function hideDropDown(){
$foo.slideUp({duration:800, queue:false}).width(0);
}

Why not chain .animate() after .slideUp()?
$foo.slideUp({duration: 800, queue: false}).animate({"width": 0}, 800);

Related

Extjs SlideOut panel

I am trying to slide out a panel and then hide it using extjs. The slideout is working fine but as soon as I add the hide function it stops working. How do I fix this.
My function is as below.
toggleSidebar : function () {
var sidebar = this.getSidebar();
if(sidebar.hidden){
sidebar['show']();
}else{
sidebar.el.slideOut('l', {
easing: 'easeOut',
duration: 200,
scope: this,
callback: this.onSidebarAnim()
});
sidebar['hide'](); // Slide works if I remove this line.
}
},
Animation is an asynchronous process, and slideOut does not block until animation has finished; in fact your code starts to animate the panel and then hides it immediately. That is why it's not working the way you expect it to.
The solution is to hide the panel after the animation has finished. That is what callback is for, except that in your original code instead of passing the function in callback property, you're calling it and assigning the result of its execution to the callback property. That is not going to work, and in fact it's going to blow up with "foo not a function" exception.
toggleSidebar: function () {
var sidebar = this.getSidebar();
if (sidebar.hidden) {
sidebar.show();
}
else {
sidebar.el.slideOut('l', {
easing: 'easeOut',
duration: 200,
scope: this,
// Pass the function itself, note no parentheses:
callback: this.onSidebarAnim
});
}
},
onSidebarAnim: function() {
this.getSidebar().hide();
...
}

clearInterval clearing two intervals

I can't run clearInterval for my functions. I use them to scroll the window by firing setInterval with function that fires scrollLeft. The code:
function scrollSpan() {
$('nav#scrolling').children().css('width',config.windowWidth/10+'px');
var inter;
$('nav#scrolling').children('span').hover(function() {
var value;
if($(this).is('.scrollLeft')) {
value = '-=50'
} else {
value = '+=50'
}
inter = setInterval(function() {
$('body, html').animate({
scrollLeft: value
}, 50);
},0)
})
$('nav#scrolling').children('span').mouseleave(function() {
clearInterval(inter)
})
}
Problem is, when mouseleave is triggered, interval doesn't stop.
Fiddle: http://jsfiddle.net/FpX4M/
You are using hover where you should be using mouseenter. When only one handler is passed to hover that handler is called both on enter and leave. So your hover is called twice (once entering and once leaving) but your mouseleave is only called once. This is why even though one interval is cleared, the other remains.
See the documentation, in particular the signature added in v1.4 which takes only a single handler (scrolldown).
EDIT: Jsfiddles with proof:
http://jsfiddle.net/FpX4M/1/
Open your console and see that the handlers trigger twice and that interval continues.
http://jsfiddle.net/FpX4M/2/
In the console you will now see only one firing of the handler and then the intervals stop on leave.
Your whole scope is a little wonky. Try something like this:
var inter;
function scrollSpan() {
$('nav#scrolling').children().css('width',config.windowWidth/10+'px');
}
$('nav#scrolling').children('span').hover(function() {
var value;
if($(this).is('.scrollLeft')) {
value = '-=50'
} else {
value = '+=50'
}
inter = setInterval(function() {
$('body, html').animate({
scrollLeft: value
}, 50);
},0)
});
$('nav#scrolling').children('span').mouseleave(function() {
clearInterval(inter)
});
You need to make sure the inter variable is accessible outside of the function. Also, generally, state functions shouldn't be assigned within functions unless you're changing them rapidly - and it doesn't look like you're detaching them anywhere. The only things that need to be in the function are things that will be repeated. Maybe add a clearInterval(inter); right before your inter = setInterval... to make sure no old intervals persist.

Jquery Animate Infinite Loop: How to Avoid Stack limit

I've got some Jquery that simply zooms in and out non-stop for a banner image. When I run this, I get a stack limit error in the browser. It still runs, but is there a way to make it only load into the stack "just in time"? When looking at the stack it loads zoomIn() and zoomOut() over and over again on the initial load until it hits the limit, page loads are really slow because of it.
$(document).ready(function(){
$bannerImg = $('.post-picture img')
function zoomIn(){
$bannerImg.animate({
width: 1500,
}, 50000,'linear');
$bannerImg.promise().done(zoomOut());
}
function zoomOut(){
$bannerImg.animate({
width: 1500,
}, 50000,'linear');
$bannerImg.promise().done(zoomIn());
}
zoomIn();
});
Update: Thanks for the answers. Using done(ZoomOut/ZoomIn) worked.
.done() expects a function reference - the function pass will be executed as soon as the promise object is resolved. Instead, you're just calling the functions (which return nothing, undefined, anyways). If you do this, the functions will continually call each other, acting as an infinite loop. Use this:
$bannerImg.promise().done(zoomOut);
// and later:
$bannerImg.promise().done(zoomIn);
DEMO: http://jsfiddle.net/G6uWs/
(I had to change the numbers to make it usable)
Reference:
http://api.jquery.com/deferred.done/
You're calling the function in .done() instead of passing it as a parameter.
$bannerImg.promise().done(zoomOut());
should be
$bannerImg.promise().done(zoomOut);
and
$bannerImg.promise().done(zoomIn());
should be
$bannerImg.promise().done(zoomIn);
Looks like you are causing an infinite loop. Luckily, the jQuery has a complete callback that you can leverage to prevent the infinite loop.
Non-stop zoom in and out banner
$(document).ready(function () {
$bannerImg = $('.post-picture img');
function zoomIn() {
$bannerImg.animate({
width: 1500
}, {
duration: 10000,
complete: function () {
zoomOut();
}
});
}
function zoomOut() {
$bannerImg.animate({
width: 100
}, {
duration: 10000,
complete: function () {
zoomIn();
}
});
}
zoomIn();
});
*Source: * jsfiddle

how to do jquery once fade out has finished?

I'm trying to fade out a div on a click but also change some css values.
the issue im having is that the values change while the fade out is happening (too early). I need the values to change once the fade out has finished:
<script type="text/javascript">
$('#r_text').click(function() {
$(".box1_d").fadeOut();
$(".box1_c").css("top","0px");
});
</script>
Now when i run that, everything works but just not exactly how i'd like it.. I need the css values to be changed once the fadeout has finished, not while it's still happening.
is this possible?
if so, any ideas how?
thank you.
Use a callback function to modify the .css() as the second parameter to fadeOut(). It will fire when the fade completes.
<script type="text/javascript">
var fadeTime = 500;
$('#r_text').click(function() {
$(".box1_d").fadeOut(fadeTime, function() {
$(".box1_c").css("top","0px");
});
});
</script>
Provided you use jQuery version >= 1.5, you can/should utilize the Deferred object instead of using the callback parameter:
$('#r_text').click((function () {
var animations = {
initial: function () {
return $(".box1_d").fadeOut(1500);
},
following: function () {
return $(".box1_c").css("top","0px").animate({fontSize: '150%'});
},
onDone: function () {
alert('DONE!');
}
};
return function(e) {
$.when(animations.initial())
.pipe(animations.following)
.done(animations.onDone);
e.preventDefault();
};
}()));
JsFiddle of it in action: http://jsfiddle.net/wGcgS/2/

How to block JQuery actions while a previous action is still taking place

I have a a div in a page that slides up on hover, and then back down on hover out. If you were then to hover in and out on the item, then all the actions will be queued and thus triggered, causing the object to keep sliding up and down even though you are no longer interacting with it.
You can see this in action on the site I am developing here. Simply hover over the large image in the center to see the information div to appear.
Ideally what should happen is that while an animation is taking place no further actions should be queued.
Here is my current code:
$(document).ready(function(){
$(".view-front-page-hero").hover(
function() {
$hero_hover = true;
$('.view-front-page-hero .views-field-title').slideDown('slow', function() {
// Animation complete.
});
},
function() {
$hero_hover = false;
$('.view-front-page-hero .views-field-title').slideUp('slow', function() {
// Animation complete.
});
}
);
});
Create a global variable. When the animation starts. Clear it when it completes. Set a condition to exit the function if this variable is set before calling the animation.
This is probably not the best solution, but if you run stop(true, true) before the animation, it should work.
Live demo: http://jsfiddle.net/TetVm/
$(document).ready(function(){
var continue=true;
$(".view-front-page-hero").hover(
function() {
if(continue){
$('.view-front-page-hero .views-field-title').slideDown('slow', function() {
continue=false;
});
}
},
function() {
if(continue!){
$('.view-front-page-hero .views-field-title').slideUp('slow', function() {
continue=true;
});
}
}
);
});
//this will make your code work correctly...

Categories