Expand and collapse a div - javascript

I have a list of items & they are holding images, each image is 800w x 600 H. The original div height is 800 W x 300 H. I figured out how to expand the div when it is clicked, but i want to know how to collapse it when you clicked it while it is already expanded. Right now i just expands the div even further
$('.expand').bind('click', function() {
var currHeight = $(this).css('height').replace(/px/,'');
currHeight = currHeight * 1;
var newHeight = currHeight + 500;
$(this).animate({
height: newHeight
},1000);
});
any idea on how to create an if else statement that would say, IF the div is already expanded then collapse on click, or if the div is collapse, then expand to # of px.

You can detect the current height and branch:
$('.expand').bind('click', function() {
var $this = $(this),
height = $this.height();
if (height > 500) {
height -= 500;
}
else {
height += 500;
}
$this.animate({
height: height
},1000);
});
I've done a couple of other things in there. You can use height rather than css('height') to get the value without units, and no need for the * 1 trick. I've also done the $(this) once and reused it, since there are multiple function calls and an allocation involved when you call the $() function. (It doesn't matter here, but it's a good habit to get into provided you're not caching it longer than you mean to [via a closure or such].)
Alternately, you can remember that you've done it another way (using the data feature):
$('.expand').bind('click', function() {
var $this = $(this),
height = $this.height(),
expanded = $this.data('expanded');
if (expanded) {
height -= 500;
}
else {
height += 500;
}
$this.data('expanded', !expanded);
$this.animate({
height: height
},1000);
});
Or combine those to store the original height in case it gets influenced by something else:
$('.expand').bind('click', function() {
var $this = $(this),
height = $this.height(),
prevHeight = $this.data('prevHeight');
if (prevHeight) {
height = prevHeight;
$this.data('prevHeight', undefined);
}
else {
$this.data('prevHeight', height);
height += 500;
}
$this.animate({
height: height
},1000);
});
Take your pick!

I would use CSS to set the height of the div in both original and expanded versions, and then when the div is clicked, toggle a class to change the height:
/* CSS for the height */
.expand {
height: 300px;
}
.expand.expanded {
height: 600px;
}
and then in the click method, just:
$(this).toggleClass("expanded");

A few pointers with jQ:
.click(function(){})
.css({height: "300*1px"}) // Why are you multiplying Anything by ONE?!
And you can use
if($(this).css("height") == "300px") {
Do stuff
} else {
Do other stuff
}
Edit: But other options above are far better.

You can check the .height() at the time of the click event and .animate() the height += or -= accordingly (something .animate() supports), like this:
$('.expand').click(function() {
$(this).animate({
height: $(this).height() > 300 ? "+=500px" : "-=500px"
}, 1000);
});
Or, use .toggle(), like this:
$('.expand').toggle(function() {
$(this).animate({ height: "+=500px" }, 1000);
}, function() {
$(this).animate({ height: "-=500px" }, 1000);
});

Pure Jquery, check the documentation Jquery Animate
$( "#clickme" ).click(function() {
$( "#book" ).animate({
height: "toggle"
}, {
duration: 5000,
specialEasing: {
height: "linear"
},
complete: function() {
//DO YOUR THING AFTER COMPLETE
}
});
});

Related

Animate progress bars upwards

I am looking to animate this progress bars, but I'm having a different behavior using jQuery animate() method. I want to animate the progress bars one by one with a 0.1s delay. I will need help with choosing the right animation, because now my animation is behaving downwards. I'd like to do it in the simplest way possible.
Here is what I have so far:
$('.vertical-bars .progress-fill span').each(function() {
var percent = $(this).html();
var pTop = 100 - (percent.slice(0, percent.length - 1)) + "%";
$(this).parent().css({
'height': percent,
'top': pTop
});
$(this).parent().animate({
height: "toggle"
}, {
duration: 900,
specialEasing: {
height: "swing"
}
});
});
I have prepared a JSFiddle with my progress bars HERE.
The right behavior is to fill the progress-bars upwards, like in THIS example.
You need to animate both the height and top of your bars, or you need to construct them such that they are pinned to the horizontal axis when you change the height. The second takes a little more thought, but the first, although not as elegant, is straight forward.
To animate top you can't use toggle (as it is animating to 100% and back, not to 0), so you will need to animate both the shrink and grow separately using done to trigger a second animation. Taking the same style as you used above:
$('.vertical-bars .progress-fill span').each(function () {
var percent = $(this).html();
var pTop = 100 - ( percent.slice(0, percent.length - 1) ) + "%";
$(this).parent().css({
'height': percent,
'top': pTop
});
var self=this;
$(this).parent().animate({
height: 0,
top: "100%"
}, {
duration: 900,
specialEasing: {
height: "swing",
top: "swing"
},
done:function(){
$(self).parent().animate({
height: percent,
top: pTop
}, {
duration: 900,
specialEasing: {
height: "swing",
top: "swing"
}
})
}
});
});
Of course you can also achieve the same thing using css animation. If I have time to figure it out I'll post an edit.
I don't know what height: "toggle" does but you basically want to set 0 height and 100% offset from top and then start animation that adjusts both styles.
The 100ms between animations is done simply by using setTimeout and incrementing the timeout.
https://jsfiddle.net/kss1su0b/1/
var elm = $(this).parent();
elm.css({
'top': '100%',
'height': 0
});
setTimeout(function() {
elm.animate({
'height': percent,
'top': pTop
}, {
duration: 900,
specialEasing: {
height: "swing"
},
});
}, animOffset);
animOffset += 100;
The simplest and most performing way to invert the animation direction is to align the bars at the bottom with css:
vertical-bars .progress-fill {
position: absolute;
bottom: 0;
}
Then you don't need to set the top any more with jQuery and set a delay:
$('.vertical-bars .progress-fill').each(function (index) {
var percentage = $(this).find('.percentage').html();
$(this).delay(index * 100).animate(
{
height: percentage
}, {
duration: 900,
done: function () {
$(this).find('span').show("normal");
}
}
);
});
jsfiddle

jQuery dynamically set incremented height to elements

What I want to achieve:
for each ul.container -> find the greatest li height -> add 25px to it -> apply that new height to all li within the container.
I need the calculation to happen also on window resize.
The problem:
While this works at page load, when resizing the browser window, the height keeps incrementing by 25px at every loop. I can't seem to figure out what I am doing wrong.
My code:
function listHeight() {
$("ul.container").each(function () {
var listHeight = 0;
var newHeight = 0;
$("li", this).each(function () {
newHeight = $(this).height();
if (newHeight > listHeight) {
listHeight = newHeight;
}
});
$("li", this).height(listHeight += 25);
});
}
listHeight();
$(window).resize(function () {
listHeight();
});
JSFiddle: http://jsfiddle.net/upsidown/VtypM/
Thanks in advance!
The height increases because you set the height in the first run. After that the height remains the "max hight" + 25 and adds additional 25 to it.
To prevent that just reset the height of the element to auto.
function listHeight() {
$("ul.container").each(function () {
var listHeight = 0;
var newHeight = 0;
$("li", this).each(function () {
var el = $(this);
el.css('height', 'auto');
newHeight = el.height();
if (newHeight > listHeight) {
listHeight = newHeight;
}
});
$("li", this).height(listHeight += 25);
});
}
listHeight();
$(window).resize(function () {
listHeight();
});
For better performance I suggest that you debounce/throttle the function call.
you need to add
$("li", this).height("auto");
after
var listHeight = 0;
var newHeight = 0;
view Demo
I think you need to look at this thread.
jQuery - how to wait for the 'end' of 'resize' event and only then perform an action?
You need to call it at the end of the resize event.
Hope it helps!
You need to increment height only if newHeight > listHeight, I think.

How to animate parent height auto when children height is modified

I have a parent div with height set to auto.
Now whenever I fade something in that's a child of that div, the height just jumps to the new height. I want this to be a smooth transition.
The height is supposed to transition before any children are being displayed, and also transition after any children are being removed (display: none;).
I know this is possible when you know the predefined heights, but I have no idea how I can achieve this with the height being set to auto.
JSFiddle Demo
You could load new content with display: none and slideDown() it in and then fadeIn with animated opacity. Before you remove it you just fade out and slideUp()
I think this is what you wanted: jsFiddle
$(function() {
$("#foo").click(function() {
if($("#bar").is(":visible")) {
$("#bar").animate({"opacity": 0}, function() {
$(this).slideUp();
});
}
else {
$("#bar").css({
"display": "none",
"opacity": 0,
/* The next two rows are just to get differing content */
"height": 200 * Math.random() + 50,
"background": "rgb(" + Math.round(255 * Math.random()) + "," + Math.round(255 * Math.random()) + "," + Math.round(255 * Math.random()) + ")"
});
$("#bar").slideDown(function() {
$(this).animate({"opacity": 1});
});
}
});
});
Try this also: jsFiddle. Click "Click me" to add new divs. Click on a new div to remove it.
$(function() {
$("#foo").click(function() {
var newCont = $("<div>").css({
"display": "none",
"opacity": 0,
"height": 200 * Math.random(),
"background": "rgb(" + Math.round(255 * Math.random()) + "," + Math.round(255 * Math.random()) + "," + Math.round(255 * Math.random()) + ")"
});
$(this).append(newCont);
newCont.slideDown(function() {
$(this).animate({"opacity": 1});
});
newCont.click(function(e) {
$(this).animate({"opacity": 0}, function() {
$(this).slideUp(function() {
$(this).remove();
});
});
return false;
});
});
});
The approach I took was to see if .bar was visible, and if so fade it out, the animate the height of #foo back to where it started, or animating it to the height of .bar + #foo otherwise, using callbacks in both cases to get the effect that you were looking for.
Code:
$(function() {
var start_height = $('#foo').outerHeight();
$("#foo").click(function() {
$bar = $('.bar');
$foo = $(this);
if($bar.is(':visible')) {
$bar.fadeToggle('slow', function() {
$foo.animate({height: start_height});
});
} else {
$foo.animate({height: ($bar.outerHeight()+start_height)+'px'}, 'slow', function() {
$bar.fadeToggle();
});
}
});
});
Fiddle.
EDIT:
Added .stop() to prevent unexpected behavior when double clicked.
Updated Fiddle.
Try to use developer tools in browsers.
All browser have nowadays it. (ctrl shift i)
If u look at page source code after fadeOut executed, u will see inline style "display:none" for inner element. This means that your inner element has no height any more, that is why outer(parent) element collapsed (height =0);
It is a feature of all browsers, that block elements take height as they need unless u will not override it. so since there are no elements inside with height more than 0 px that height of parent will be 0px;
y can override it using css style
height: 300px
or
min-height: 300px;
This is correct if u use jquery
Try this fix :)
$(function() {
var height = $("#foo").height();
$("#foo").click(function() {
var dis = $(".bar").css('display');
if(dis == 'none'){
$(this).animate({height:height+$(".bar").height()},2000,function(){
$(".bar").show();
});
}
else{
$(".bar").hide();
$(this).animate({height:height-$(".bar").height()},2000);
}
});
});
#foo {
height: auto;
background: #333;
color: white;
min-height: 20px;
}

jQuery scrollTop being buggy

I'm trying to make a sub navigation menu animate a fixed position change after a user has scrolled down 200 pixels from the top. It works but it's very buggy, like when the user scrolls back to the top it doesn't always return to the original position, etc. I'm not strong with javascript / jquery, but I thought this would be simple to do. What am I missing?
Here's my fidde:
http://jsfiddle.net/visevo/bx67Z/
and a code snippet:
(function() {
console.log( "hello" );
var target = $('#side-nav');
var scrollDis = 200;
var reset = 20;
var speed = 500;
$(window).scroll(function() {
console.log( $(window).scrollTop() );
if( $(window).scrollTop() > scrollDis ) {
$(target).animate({
top: reset + 'px'
}, speed);
} else {
$(target).animate({
top: scrollDis + 'px'
}, speed);
}
});
})();
How about a little bit of css and jquery both ??
What I did is added transition to side-nav to animate it and rectified your js to just change it's css. You can set how fast it moves by changing the time in transition.
FIDDLE
#side-nav {
position: fixed;
top: 100px;
left: 10px;
width: 100px;
background: #ccc;
-webkit-transition:all 0.5s ease-in-out;
}
(function () {
var target = $('#side-nav');
var scrollDis = 100;
var reset = 20;
var speed = 500;
$(window).scroll(function () {
if ($(this).scrollTop() >= scrollDis) {
target.css("top", reset);
} else {
target.css("top", scrollDis);
}
});
})();
NOTE: When you cache a jQuery object like this
var target = $("#side-nav");
You don't need to use $ again around the variable.
Since I am commenting all over the place I should probably actually contribute an answer.
The issue is that you are adding scroll events every time a scroll occurs, which is causing more scrolling to occur, which causes more scroll events, hence infinite loop. While cancelling previous events will fix the problem, it's cleaner to only fire the event when you pass the threshold, IE:
(function () {
console.log("hello");
var target = $('#side-nav');
var scrollDis = 200;
var reset = 20;
var speed = 500;
var passedPosition = false;
var bolMoving = false;
$(window).scroll(function () {
if (bolMoving) return; // Cancel double calls.
console.log($(window).scrollTop());
if (($(window).scrollTop() > scrollDis) && !passedPosition) {
bolMoving = true; //
$(target).animate({
top: reset + 'px'
}, speed, function() { bolMoving = false; passedPosition = true; });
} else if (passedPosition && $(window).scrollTop() <= scrollDis) {
bolMoving = true;
$(target).animate({
top: scrollDis + 'px'
}, speed, function() { bolMoving = false; passedPosition = false; });
}
});
})();
http://jsfiddle.net/bx67Z/12/
http://jsfiddle.net/bx67Z/3/
I just added .stop() in front of the .animate() , and it works a lot better already.
$(target).stop().animate({
top: reset + 'px'
}, speed);
} else {
$(target).stop().animate({
top: scrollDis + 'px'
}, speed);
You can also use .stop(true)
http://jsfiddle.net/bx67Z/5/
$(target).stop(true).animate({
top: reset + 'px'
}, speed);
} else {
$(target).stop(true).animate({
top: scrollDis + 'px'
}, speed);
You can also use .stop(true, true)
http://jsfiddle.net/bx67Z/4/
$(target).stop(true, true).animate({
top: reset + 'px'
}, speed);
} else {
$(target).stop(true, true).animate({
top: scrollDis + 'px'
}, speed);
So the reason .stop(true) works so well, is that it clears the animation queue. The reason yours was being "buggy" is because on every scroll the animation queue was "bubbling up" , thus it took a long time for it to reach the point where it would scroll back to the original position.
For information about .stop() , see here http://api.jquery.com/stop

Change menu option width with jQuery

I have got a menu on my homepage and on hover I would like them to enlarge. This is exactly what I have achieved, except there is one flaw:
When I move off before the animation ends, the option stops the animation and subtracts 30 from the width that left off from the previous animation. So it always intersects with the other animation and causes false results.
Example:
I move quickly to menu option 1, it only expands little - let's say by 10px - while I am on it, and as I move off the width decreases by 30px, which is more than the previously moved 10px, which results in a smaller button overall.
I would like to somehow capture how much it has moved during the mouseover animation and only decrease the width in the leaving function by that amount. Or, of course some other easy solution, if there is one...
Here's the code:
$('.menu_option').hover(
function() {
var w = $(this).width()+30+"";
$(this).stop().animate({ width:w}, 150, 'easeOutQuad');
}, function() {
var w = $(this).width()-30+"";
$(this).stop().animate({ width:w}, 150, 'easeOutQuad');
});
What you can do is make another variable which is the origin width then when you put it back go back to the origin:
js:
var o = $('.menu_option').width();
$('.menu_option').hover(function () {
var w = $(this).width() + 30 + "";
$(this).stop().animate({
width: w
}, 150, 'easeOutQuad');
}, function () {
$(this).stop().animate({
width: o
}, 150, 'easeOutQuad');
});
http://jsfiddle.net/Hive7/qBLPa/6/
You need to complete the previous animation before the width is calculated
$('.menu_option').hover(function () {
var $this = $(this).stop(true, true);
var w = $this.width() + 30;
$this.animate({
width: w
}, 150, 'easeOutQuad');
}, function () {
var $this = $(this).stop(true, true);
var w = $this.width() - 30 + "";
$this.animate({
width: w
}, 150, 'easeOutQuad');
});
Demo: Fiddle

Categories

Resources