Getting the nearest positioned ancestor of an Element - javascript

According to https://www.w3schools.com/css/css_positioning.asp,
An element with position: absolute; is positioned relative to the nearest positioned ancestor (instead of positioned relative to the viewport, like fixed).
How can I get the nearest positioned ancestor of an Element, in either vanilla Javascript or JQuery?
What about offsetParent()? https://api.jquery.com/offsetParent/
Description: Get the closest ancestor element that is positioned.

You can test if the position is static of the parent, if not you continue until your reach the first ancestor with position different from static.
Here is a simplified code that you can adjust:
$('.box').each(function() {
var p = $(this).parent();
while (p && p.css('position') === 'static') {
p = p.parent();
}
console.log(p.attr('class'));
})
.box {
position: absolute;
}
.f2 {
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="f1">
<div class="f2">
<div class="f3">
<div class="box"> <!-- This one relative to f2 -->
<div class="box"> <!-- This one relative to box -->
</div>
</div>
</div>
</div>
</div>
<div class="f1">
<div class="f2">
<div class="f3" style="position:absolute;">
<div class="box"> <!-- This one relative to f3 -->
</div>
</div>
</div>
</div>

Edit : I was assuming you were looking for distance bewteen two elements. #TemaniAfif has the right answer
You could navigate the tree of ancestors using parentNode and compare the offsetTop of each to the offsetTop of the element at hand. if all you are interested in is the Y distance.
On the other hand if you need the full distance while accounting for X and Y, you could use the method described here
Measure distance between two HTML elements' centers

Related

JQuery Resize - Bring to Front

I've made several overlapping objects draggable and resizable via the JQuery Draggable and Resizable plugins. When dragging an object, it's instantly brought up to the frontmost position thanks to the stack option. The Resizable plugin doesn't have this option so when an element in the background is being resized but not dragged, it stays in the back.
How do I make an object being resized jump to the front just like it happens when it's being dragged?
Thanks
You can implement this yourself by using the start event of the resizable widget.
In that event you just loop through your draggable/resizable elements to find the highest zIndex, then set your currently resizing element higher in the stack.
For example (heavily commented for clarity).
// Common class of our draggable/resizable elements
const targetClass = ".foo";
$(targetClass)
.resizable({
start: (event, ui) => {
// current resizing element
const element = $(ui.element[0]);
let topZIndex = 0;
// loop over all our elements
$(targetClass).each((i, obj) => {
// get the current zIndex as an int, using the unary operator
// and accounting for NaN values like 'auto'
const currentZIndex = +$(obj).css("zIndex") || 0;
// if current zIndex is higher, update the topZIndex
currentZIndex > topZIndex && (topZIndex = currentZIndex);
});
// set the resizing elements zIndex above the highest
element.css("zIndex", topZIndex + 1);
}
})
.draggable({
stack: targetClass
});
.foo {
width: 100px;
height: 100px;
padding: 0.5em;
position: absolute !important;
}
.foo h3 {
text-align: center;
margin: 0;
}
<script src="https://code.jquery.com/jquery-3.6.0.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.13.2/themes/base/jquery-ui.css">
<div id="container">
<div class="foo ui-widget-content">
<h3 class="ui-widget-header">test 1</h3>
</div>
<div class="foo ui-widget-content">
<h3 class="ui-widget-header">test 2</h3>
</div>
<div class="foo ui-widget-content">
<h3 class="ui-widget-header">test 3</h3>
</div>
</div>

JsPlumbĀ“: if source `div `is child of `div` with `position:absolute` -> targed endpint wrong drawn

I have the following setup: https://jsfiddle.net/b6phv6dk/1/
It basically contains two blue div elements with jsPlumb connectors.
The source div is the child of a third black div element that has an offset of 100px from the top, applied with position: absolute;.
It seems like jsPlumb takes the difference in position of the black div to the blue source div ( which is 0px ) and draws the connection according to this absolute position of the blue source div ( because the targed endpoint would be right if the blue sourcedivwould be at the global position0px 0px`):
If I remove the position: absolute; from the blackDiv the target endpoint is drawn correct, but I have a setup where I have nested div elements that hold their relative position to each other by:
.item {
position: absolute;
top: value;
left: value
}
Try encapsulating all elements in a container:
<div id="container">
<div class="blackDiv">
<div id="item_left" class="item"></div>
</div>
<div id="item_right" class="item" style="top: 100px; left:250px;"></div>
</div>
and setting it on the jsplumb instance:
jsPlumb.setContainer("container");
https://jsfiddle.net/b6phv6dk/2/

Detect if child divs are wider than parent?

How can I detect if multiple child divs are wider than their parent? In this case, when they are wider, the rightmost one is displayed below the leftmost one. I have tried using js to check for an overflow (as described here: javascript css check if overflow), but it doesn't work.
Ultimately, I want to keep the rightmost div below its sibling and change its padding, but only when they are wider.
The code is basically this:
<div class='parent'>
<span>title</span><br />
<div class='child'>
Some content.
</div>
<div class='child'>
More content that sometimes doesn't fit.
</div>
</div>
not sure, but have you tried it?
var children = YourParentDiv.children;
for (var i = 0; i < children.length; i++) {
var child_width=children[i].offsetWidth;
var parent_width = children[i].parentElement.offsetWidth;
if (child_width>parent_width)
{console.log('wider');}
}
This will compare the child width and the parent width of your divs
$('.parent').children('.child').each(function() {
let $this = $(this);
console.log($this.width(), ' ', $('.parent').width());
if ($this.width() > $('.parent').width()) {
//add the padding you want
$this.css('padding-top', '10px');
}
})
.parent {
width: 500px;
}
.child {
background-color: green;
width: 700px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div class='parent'>
<span>title</span>
<br />
<div class='child'>
Some content.
</div>
<div class='child'>
More content that sometimes doesn't fit.
</div>
</div>

Last created DIV to be above other DIVs

I'm creating DIVs dynamically and appending them to a particular DIV.
My question is how do I always make the last created DIV to be above other DIVs within the appended (its parent) DIV?
So basically I want the last created DIV to be on the top level of the other.
DIV 4 - [created at 4:32pm]
DIV 3 - [created at 4:29pm]
DIV 2 - [created at 4:27pm]
DIV 1 - [created at 4:26pm]
the dynamic DIV css:
.dynamicDIV{
width:100%;
position: relative;
}
the append DIV css:
.parentDiv{
width: 100%;
margin-top: 5px;
}
I'm not referring to the z-index. I want to position it above the others.
var parentElement;
var newFirstElement;
parentElement.insertBefore(newFirstElement, parentElement.firstChild);
As I pointed out in my comment, .prepend() can be used here:
$('.parentDiv').prepend('<div class="dynamicDIV">New Div</div>');
but there is a second possibilty:
$('<div />').addClass('dynamicDIV').text('New Div').prependTo('.parentDiv');
This solution is a bit more maintainable.
Demo
Reference
.prepend()
.prependTo()
Use .prepend() on whatever element you want to be preceeded with the new one:
http://api.jquery.com/prepend/
When a DIV is at position: absolute, the last sibling in the DOM is over the others. This doesn't depend on the time you inserted it.
But you can override this behavior by using z-index: 1.
Look at this HTML code:
<style>
div.container > div {position: absolute; z-index: 0}
div#C {z:index: 7}
</style>
<div class="container">
<div id="A">A</div>
<div id="B">B</div>
<div id="C">C</div>
<div id="D">D</div>
</div>
This code will display C hidding D, hidding B, hidding A.
CSS with display:flex and flex-direction:column-reverse; can help you:
body {/* parent container of div to shw in a reverse flow*/
display:flex;
flex-direction:column-reverse; /* row-reverse if on line*/
}
div {
width:50%;
border:solid;
margin:auto;
}
div:last-of-type:after {
content:'last in document !';
color:red;
}
<div> 1 </div>
<div> 2 </div>
<div> 3 </div>
<div> 4 </div>
anyway, in the DOM or for CSS selector, last will be last. reverse order only shows at screen.

Get offset from element other than parent?

Using element.offset().left gets you the element's offset position from its parent. Is there any way to get the offset position from another element? For example, here's my html:
<div id="tile_id_579" class="product_tile">
<div class="selectContainer">
<table style="width:100%;">
<tbody>
<tr>
<td>
<div id="select-undefined" class="tzSelect">
<div id="options-undefined" class="tzOptions" style="max-height: 500px; width: 250px; display: none; min-width: 118px;">
<ul class="dropDown" id="dropdown-undefined">
<li><div class="header">Hand-Tossed Style Pizza</div>
<div class="subheader">The crowd-pleasing pizza that everyone can agree on.</div>
<div class="optkey">0</div>
</li>
<li><div class="header">Pan Pizza</div>
<div class="subheader">Our Pan Pizza is America's favorite!</div>
<div class="optkey">1</div>
</li>
</ul>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
It's generated from a database. Using offset().left gets me the offset from the #selecct-undefined div, but I need to get how far the #options-undefined div is from the .selectContainer div. Is this possible?
EDIT TO ADD
Tried both of these, and both return the same thing: top: 381, left: 0. But left is NOT 0 in relation to the document; it can't be.
var tip = $('#tile_id_579 #options-undefined .header');
tip.first().position();
and
var tip = $('#tile_id_579 #options-undefined .header');
tip.first().offset();
How is it possible that left is 0 for both when this is where the div is? Doesn't 0 left imply that it's all the way at the left of the browser window?
Since your element is indeed within that parent you specified you can use .position() instead of .offset(). But if .selectContainer is not the closest relative parent you will need to get the position of both your element and that "other" element and calculate the difference.
var myPos = $('#options-undefined').offset();
var otherPos = $('#options-undefined').closest('.selectContainer').offset();//if #options-undefined wasn't a child of .selectContainer you would do $('.selectContainer').offset();
var _offset = {
top: otherPos.top - myPos.top,
left: otherPos.left - myPos.left
}

Categories

Resources