Get height of DIV and its content with JQuery - javascript

I have a div which contains several elements:
<div class="menuItem designMenu" id="dMenu">
<ul class="menuList menu">
<li class="menuHeader">Design</li>
<li class="projectHeader">Mother</li>
<li class="projectBody">Some text here</li>
<li class="more">More</li>
</ul>
</div>
I need to get the height of the dMenu items that I can animate it upwards, including all the content inside. My Javascript currently:
var designHeight = $("#dMenu").height();
Returns nothing.
I've tried offsetHeight, scrollHeight, and everything else Google turns up. I'm running the jQuery at the end of the body, inside a document ready function.
The reason to get the height to animate, instead of doing it manually, is that a: I'd like to learn how and b: I don't yet know how many items will be in the div.

Are the lis within the ul floated? If so, and the parent does not have overflow: hidden the parent collapses and therefor has no height. Try (if possible) adding overflow: hidden to the parent element, or hard code a height in your CSS.

I'm using scrollHeight to get at what I want. I also, embarrassingly, noticed as I was fiddling with things I was loading my JS before loading JQuery. So ashamed I didn't spot that.

Related

Why does element prepend removed scroll position?

I have a structure like
<div id="parent">
<div>...</div>
<div>...</div>
<div>...</div>
<div>...</div>
</div>
Where the children of parent are scrollable.
If I take on of the elements from inside parent after scrolling.
const child = parent.children[3];
I have a scroll position
child.scrollTop; // Maybe 269px
And when I add it back
parent.prepend(child);
The child looses its scroll position
child.scrollTop; // 0px
My question here is, why does the scroll position get lost in this case?
Full demonstration of what is happening.
Because when you prepend(element) it's actually first removed from the DOM then reinserted at the new position. While it's removed from the DOM, it doesn't have a CSS box anymore, no defined size, no scrolling box. When appended again all the scrolling info is reset.
const elem = document.querySelector("ul");
elem.scrollTop = elem.scrollHeight;
console.log("before", elem.scrollTop);
elem.remove();
console.log("after", elem.scrollTop);
console.log("scrollHeight", elem.scrollHeight);
console.log("height", elem.getBoundingClientRect().height);
ul { max-height: 50px; overflow: scroll }
<ul>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
<li>item</li>
</ul>
Note that there is an active discussion to maybe add a "move" operation to the DOM APIs, but it's not quite sure yet what this would look like, nor if it would solve this use case.
If you wish to maintain the scrolling position, you'd have to store it before calling .prepend() and set it back after.
Without the full demonstration I would have never understood what you were talking about.
You're moving an child. In other words you first remove it and then you insert it. Once an element is removed, scrollTop makes no sense and is reset.
A solution is to scroll the element down again after it has been inserted:
app.prepend(lastChild);
lastChild.scrollTop = lastChild.scrollHeight;
That seems to work fine.

collapsing an accordion "li" when class is removed

I've been trying to sort through this for a while now, can't seem to get it working 100%. The current code reveals the .content area without any collapse. It also shifts the page down to center on the content (which in this case goes under the fold if you don't).
$(document).ready(function() {
$('.vl-option .vl-toggle-link').click(function(e) {
e.preventDefault();
$(this).closest('li').find('.content').not(':animated').slideToggle();
$(this).closest('li').toggleClass('active');
});
$('.vl-option').bind('click',function(){
var self = this;
setTimeout(function() {
theOffset = $(self).offset();
$('body,html').animate({ scrollTop: theOffset.top - 20 });
}, 310);
});
});
I've attempted a few approaches to no avail. I'll list a few below (concept was to find any siblings and collapse):
$(this).siblings('li').find('.content').slideToggle();
which actually breaks the original functionality. Then I went with the following (to try an make anything without class="active" collapse):
if ( $(this).siblings('li').not('.active').find('.content').slideToggle(); ) //also tried .hide()
which doesn't seem to have any affect on anything.
The HTML is simple
<ul>
<li class="lv-option active"><!-- when toggled, "active" class is applied... -->
Yada
<div class="content"></div>
</li>
<li class="lv-option"><!-- ...when untoggled, "active" class removed -->
Yada yada
<div class="content"></div>
</li>
</ul>
.active is only applied for stylistic reasons. it has no effect on the functionality of anything. Just needed to be able to target the :before / :after when something was selected.
I just can't seem to wrap my head around jquery... argh.
Only one content at a time should be opened in an accordion right, so applying .slideToggle() to all <li> contents will break this rule. I think it's okay with your markup since you only have two <li>, so they just slides alternately. But if you have more I think the active <li> only should be .slideToggle() other should be .slideUp() only.
You can just chain them all:
$('.vl-toggle-link').click(function(e) {
e.preventDefault();
//find the sibling content apply slideToggle, then move to their parent and add active
$(this).siblings('.content').slideToggle().parent('li').addClass('active')
// go through all the siblings of their parent and remove active, then slideUp their child content
.siblings('li').removeClass('active').children('.content').slideUp();
});
I also find your .animate({scrollTop}) not working properly because it's obtaining the old offset().top value. I think you should get the offset().top after the slideToggle() has finished. See this jsfiddle.
Or you can also calculate scrollTop: jsfiddle.

Getting dynamic css top value from element using jQuery

I am using the jScrollPane jQuery plugin in a project, and the scrollable area has a couple of list item elements, and each list item when is clicked it needs to trigger a modal box positioned absolute from in the center, filling all the space. Anyway its kind of hard to explain, but this is not the problem. The problem is that, I need to get the negative top css value (when it scrolls down) via jQuery and I can't manage to make it work, i tried using the .css() selector but it always returns 0px even if in the source shows different. Any idea ?
EDIT:
<div id="provider-menu">
<ul>
<li class="menu-item"> <h2> content here </h2>
<div class="more-info">
more info box here
</div>
</li>
<!-- More List Items Here -->
</ul>
</div><!-- end #provider-menu -->
<!-- Javascript -->
$("#provider-menu").jScrollPane();
// jspPane is added by the plugin
var topValue = $(".jspPane").css("top"); // returns 0px every time on scroll even if in the source is different.
I am trying to do this because I can't change the HTML structure, the .more-info div has to fill the #provider-menu box which has a predefined width and height, but if I set it to absolute top left right bottom it goes to top and you have to scroll to see what's there. So I was thinking on getting the top negative value, remove the minus and set the top value to the .more-info box.
$(element).css behaves differently than you might expect.
This actually works: $(".jspPane")[0].style.top
What you have demands absolute positioning I believe, which jspPane does not have.
Either way, the above code gives you that actual ( usually negative ) pixel value.

Scrolling a <div> to Specific Content

I'm creating a split page with a menu on the left, and the main content on the right. When I click on a menu item, I want to scroll the main content to that item.
I found JavaScript scrollTo(), which takes offset arguments.
Is there any way to determine the offset of a particular <p> or other element within a <div>? Or perhaps there is another way to scroll to an element without knowing its offset?
EDIT
Thanks for the replies. Looks like everyone gave similar answers. However, I ran into a problems with this. It seems that offset().top (or position().top) return different values depending on the current scroll position.
My jsFiddle is here: http://jsfiddle.net/gBTW9/4/embedded/result/
If I scroll to the top and selection Section 4, it works as expected. But once I've scrolled, it stops working correctly. Can anyone see what is happening.
There are jquery methods offset and position stat can help there.
Also there is good scrollTo plugin which accepts elements and much more.
You can get the vertical offset of an element using $('p').offset().top. You can combine this with scrollTop() using this:
$('div').scrollTop($('p').offset().top);
You need to use position() rather than offset(). If you know the id of that you can easily find the position of that paragraph tag
jQuery: Difference between position() and offset()
If i didn't misunderstood you just need an animated scrolling to a particular element, something similar on what I did on my portfolio.
Assuming that the menu on the left is fixed, then just scroll the page to the element you want to scroll to:
$("html, body").animate({
scrollTop: $('#element').offset().top
});
If you need to move a particular element over another element then:
$("#element1").animate({
top: $('#element2').offset().top
});
Why try it the hard way, when you can use a HTML native attribute??
call me old school, but i like to keep it simple.
within your menu:
use:
<ul>
<li>
Paragraph 1
</li>
</ul>
instead of
<ul>
<li>Paragraph 1</li>
</ul>
this will make your section jump to the # (id) that equals Paragraph1

How to find the dimensions of a dom-node before creating it?

There is a <ul> list that I'm retrieving via XHR and inserting into another node (<div>). This list has a different number of elements every time (so the height of the resulting node varies).
I'd like to animate the <div> into which I'm inserting that list as it takes the new height. So, say the div was initially 100px, and the height of the XHR-retrieved list is going to be 150px, the <div> should smoothly expand to the new height of 150px.
To do this, I need the height of the rendered list (taking all the page styles into account) before it is actually rendered. Question: (a) how would you find the height, (b) do you see another way of doing this animation, and (c) is this at all possible?
a) as far as i know it isn't possible to accurately determin the height of a not yet rendered element
b) With jQuery's >slideUp> and slideDown this is perfectly doable, are you using a framework?
c) yes, you might have to put a wrapper div around the depending on the way you do it.
More:
By putting a wrapper <div> around your <ul> and setting th <div> to height:0 and overflow:hidden you can perfectly render the <ul> in it without showing it. Then you have plenty of time for javascript to get the dimensions of the <ul> and animate/resize the wrapping <div> to the <ul>'s height without ever showing your <ul>.

Categories