jQuery; Trace the height of an element which is animating via slideDown() - javascript

I'm animating an element in jQuery and I need the also animate the margin of another element to follow the height of the animating element while it slides down.
So for example, the slideDown() function starts on element x, and somehow the animate function of the corresponding element knows element x's height as it slides down and copies it, animating in unison.
Hopefully I've explained it well, let me know if you want more clarity.

You may use step property:
$("#first").animate({ /* properties */ }, {
step : function() {
var height = $(this).height();
$("#second").css("margin-top", height);
}
});

Related

Add item to top of list and scroll down

I feel this should be simple, but I can't get my head round how to do it.
I want to add new items to the top of a list, and have the list scroll down to reveal the new item.
The closest I've got so far is here: http://jsfiddle.net/philgyford/cmsh0zoz/4/ This creates and adds a new list item by doing:
var content = 'Hello';
if (Math.random() < 0.3) {
content += '<br/>Another line';
};
$('<li>').html(content)
.hide()
.prependTo( $('ul') )
.slideDown('slow', function() {
// Remove final element:
$('ul').find('li:gt(9)').remove();
});
That reveals the new item by having it slideDown, which isn't quite what I want - I want it to be as if the new item has appeared behind the "Test list" heading, and then the whole list slides down to reveal it.
Note that list items have varying heights, which complicates things slightly.
Instead of using slideDown, considering animating the ul's top margin, starting with the negative height of the newly-added element (including padding).
First, add this to your h1 style:
position: relative;
That effectively puts the h1' on top of the ul. (See css positioning z-index negative margins for why we can't use z-index for this.)
You can then animate the ul like this:
function scroll() {
var content = 'Hello';
if (Math.random() < 0.3) {
content += '<br/>Another line';
};
$('ul').prepend('<li>'+content)
.css('margin-top',-$('li').first().outerHeight(true))
.delay(1000)
.animate({'margin-top':0},
function() {
$(this).find('li:gt(9)').remove();
scroll();
}
);
};
Calling the scroll function after the animation is finished may be better than using setInterval, because it guarantees that scrolling won't occur until after the previous scroll. The delay keeps it from running continuously.
Fiddle at: http://jsfiddle.net/w0gnzqx6/8/

Choosing Parent Height With white-space:nowrap

So I have these DIVs which I have arranged to slide left an right inside of the parent.
See the following JSFiddle to see the design:
http://jsfiddle.net/StevP/C9WL7/
You can see that by adjusting the margin-left of the first child DIV by multiples of -100%, it's rather simple to correctly horizontally position the DIVs inside the parent. Therefore, it's very easy to animate.
Now, this brings me to my issue. I'm using jQuery to move them left and right. It works great. However, I'd like to choose which child the parent gets its height from.
I know, I can just add...
$('#parent').height($('.child:eq()').outerHeight());
...Which is what I have it currently doing. However, the contents of the children are likely to change causing them to resize (by animate) and, therefore, be cut off. So, having a set height isn't a possibility.
I need to use height:auto; on the parent and somehow cause it to ignore the heights of specific children. I can't for the life of me think of a way.
I don't want to use a timer and onresize/.resize() don't seem to work with my Chrome.
You could use jQuery to monitor the DOM subtree and adjust the height of your parent div in the callback like this:
$('.content').bind('DOMSubtreeModified', function(e) {
if (e.target.innerHTML.length > 0) {
$(".parent").height($(".content").height());
}
});
Here's a working jsfiddle: http://jsfiddle.net/9386d/
And a question explaining the dom subtree: jQuery watch for domElement changes?
jQuery docs for bind(): http://api.jquery.com/bind/
Well... To be perfectly honest I'm not really a huge fan of jQuery anymore so I feel bad offering this answer. It just feels so frik'n inefficient, but here is a solution that does three things: 1) it resizes the hight of the container on step and uses a CSS transition attribute for eye candy (works just as well without). 2) it sets the child height of all but the current child to 0 and uses overflow:hidden so they don't affect the flow of the document anymore. 3) it resets these children to automatic height on animation start so they are visible during transition. All I can say is "yuck", but it does work.
CSS
.child{
...
overflow:hidden;
}
jQuery
var animation_prefs = {
duration: 3000,
start: function() {
$('.child').height('auto');
},
step: function(now) {
var current_index = (Math.floor((now + 50) / 100) * -1);
$('#parent').height($('.child:eq(' + current_index + ')').outerHeight());
$('#parent').data('current', current_index);
},
complete: function() {
$('#parent').height('auto');
$('.child:not(:eq('+$('#parent').data('current')+'))').height(0);
}
}
$('.child:eq(0)').animate(
{
marginLeft:'-200%' //~ Move it back 2 children
},
animation_prefs
).animate(
{
marginLeft:'-100%' //~ Move it back 1 child
},
animation_prefs
).animate(
{
marginLeft:'-200%' //~ Move it back 2 children again
},
animation_prefs
);
Demo
http://jsfiddle.net/Gq4xs/show
Source
http://jsfiddle.net/Gq4xs/

jQuery animate on property change

I have I div or some other element which I load content into with:
$('#my_div').load('ajax.php',function(){
//Do random stuff.
}
However the height of the div will then change, causing the page to jump up and down, looking ugly.
Is there a way for it to animate the height when the new content is loaded or changed? I know one can do this with FluidMoveBehavior in C#.
How can I achieve the same effect with Javascript/jQuery?
Here's some Fiddle
When you want to create a height or width animation with jQuery you have to set a number indicating the desired size. I assume that you use height: auto in this case so you have to find a little workarround.
Get the height:
var autoHeight = $("#content").height("auto").height();
Animate to autoHeight:
$("#content").animate({height: autoHeight}, 1000);
And together:
var currentHeight = $("#content").height();
var autoHeight = $("#content").height("auto").height();
$("#content").height(currentHeight);
$("#content").animate({height: autoHeight}, 1000);
Stolen from here
What I do is the opposite. I animate the page to scroll to the top if not already BEFORE I call the load.
So that the top of any new dynamic content is always in view.
I know this isn't the answer you were looking for, but I've found it works best.
You could hide #my_div before the load(), and then slideDown() in the complete function:
$('#my_div').hide().load('ajax.php', function() {
$(this).slideDown();
});
Or, create a temporary element, hide it, append it, use its height to animate #my_div once the load is complete, and then remove it.
$('<span/>').hide().appendTo('body').load('ajax.php', function(text) {
$('#my_div').animate({ height: $(this).height() }, '800').html(text);
$(this).remove();
});

jQuery - delete element if exists body area

I am using jQuery animate to change the position of multiple elements on the page (decorative elements). I want the element to be deleted if it exits body area. (if left is larger than body width or top is larger than body height).
The following can not be used in my case:
overflow hidden for the body
manually animating the element. I want to use jQuery animate to keep it simple (I dinamically create elements, animate them then I don't care about them, don't keep track of them, they have a .remove() methode when the animation is complete)
http://jsfiddle.net/a7Nck/
So in this JSfiddle I want the red div to dissappear when it reaches right edge of the body so that no scrollbars will appear.
Isn't there any CSS3 media query for example so that if a div is not in the viewport it will be hidden?
EDIT:
I just thought of a solution: get the width of the body prior to triggering the animation and then animate the top and left by using the minimum between the body size and what the animation should do. The problem is that this will affect animation speed.
You can use animate's step function.
The second version of .animate() provides a step option — a callback function that is fired at each step of the animation. This function is useful for enabling custom animation types or altering the animation as it is occurring. It accepts two arguments (now and fx), and this is set to the DOM element being animated.
var w = $(window).width()
$('div').animate({
left: '20px'
}, 500).delay(1000).animate({
left: '2000px'
}, {
step: function(now, fx) {
if (now > w) {
$(fx.elem).remove()
}
}
}, 1000);
Fiddle
One possible workaround (assuming your first restriction is about globally adding overflow: hidden on your CSS): add overflow: hidden with js when the animation starts, and remove it when it ends:
$('body').css('overflow', 'hidden');
$('div').animate({left: '20px'},400).delay(1000).animate(
{left: '2000px'},1000, false, function(){
$(this).hide();
$('body').css('overflow', 'auto');
});​
http://jsfiddle.net/a7Nck/3/
Just hide the div when the last animation get completed i.e.
$('div').animate({left: '20px'},400).delay(1000).animate({left: '2000px'},1000, function(){ $(this).hide(); });
See DEMO
As soon as the div leaves the visible area, the scrollbar will appear. If you want to prevent the scrollbar from appearing, you can't allow the div to leave the screen. Here's my solution:
$('div')
.animate({left: '20px'},400)
.delay(1000)
.animate(
{left: ($(window).width()-$('div').width()) + "px"},
1000,
null, // default easing
function() { $('div').hide() }
);
Jsfiddle: http://jsfiddle.net/j4rdA/1/
​

Animating the height of a continer on jQuery.load()

I'm using $('#container_div').load(url) to populate a div via ajax. I would like to animate the height to the height of the returned content but really cant figure out how to achieve this.
I've tried using something like this:
$('#main').fadeOut(function() {
$('#main').load(url, function(data) {
var newHeight = $(data).height();
$('#main').animate({height:newHeight}, function() {$('#main').fadeIn();});
});
});
But can see that this is wrong on so many levels. Especially due to the fact that newHeight === undefined.
Can anybody point me in the right direction here? I would be eternally grateful.
Since fadeOut() finishes by hiding the target elements, chances are your #main will be completely hidden by the time your new data is loaded, rendering any animation of height invisible, and therefore pointless.
But you could just use something like $('#main').show(400) which will animate the element from a size of (0,0) and opacity of 0 to whatever size is allowed by the container and contents and a fully-visible opacity of 1 (and run these animations in parallel, making both of them visible).
But assuming you do care more about animating the height than you do about fading, you still have a problem: by the time load() calls its callback, the height of the target element(s) will already be the height of the content (or as close as possible to it). So animating won't do anything.
I posted a plugin on a previous question that will do what you want, but you'll need to use $.get() instead of load():
$.get(url, function(data) {
$('#main').showHtml(data);
});
...where showHtml is defined as:
// Animates the dimensional changes resulting from altering element contents
// Usage examples:
// $("#myElement").showHtml("new HTML contents");
// $("div").showHtml("new HTML contents", 400);
// $(".className").showHtml("new HTML contents", 400,
// function() {/* on completion */});
(function($)
{
$.fn.showHtml = function(html, speed, callback)
{
return this.each(function()
{
// The element to be modified
var el = $(this);
// Preserve the original values of width and height - they'll need
// to be modified during the animation, but can be restored once
// the animation has completed.
var finish = {width: this.style.width, height: this.style.height};
// The original width and height represented as pixel values.
// These will only be the same as `finish` if this element had its
// dimensions specified explicitly and in pixels. Of course, if that
// was done then this entire routine is pointless, as the dimensions
// won't change when the content is changed.
var cur = {width: el.width()+'px', height: el.height()+'px'};
// Modify the element's contents. Element will resize.
el.html(html);
// Capture the final dimensions of the element
// (with initial style settings still in effect)
var next = {width: el.width()+'px', height: el.height()+'px'};
el .css(cur) // restore initial dimensions
.animate(next, speed, function() // animate to final dimensions
{
el.css(finish); // restore initial style settings
if ( $.isFunction(callback) ) callback();
});
});
};
})(jQuery);
It's because $(data) isn't in the DOM, however $(this) is :)
$('#main').fadeOut(function() {
$('#main').load(url, function(data) {
var newHeight = $(this).height();
$(this).animate({height:newHeight}, function() {$(this).fadeIn();});
});
});
However the new height will already be what it's doing to be at this point, and you can't guess the height of the new content because it's all determined by it's container, you may be better off storing and restoring it, something like this:
$('#main').animate({ opacity: 0 }, function() {
var height = $(this).height(); //previous height
$('#main').load(url, function(data) {
var newHeight = $(this).height(); //new height
$(this).height(height) //set old height before animating to new
.animate({height:newHeight})//animate to new height
.fadeIn(); //fade is a queued animation
});
});
I'm animating the opacity here so the display:none doesn't get applies, making this much simpler overall.
First, load your data into a temporary div, which you have hidden way to the left and the top of the page with absolute positioning. You can then get the height of that (as long at it's height in the css is set to 'auto'. Use that height information to animate the div you are showing. Finally, don't forget to remove the temporary div from the dom and set the height of the div you show to 'auto' once the animation is complete.

Categories