className on children affects parent element - javascript

Im building a card object and I want it to have the className .card which is defined in css like this:
.card img{position:absolute; width:150px; height:160px}
which mean I want only the images inside my div to cover each other and not the div's themselves. Every time a create 2 or more cards, they cover each other as if they had the position: absolute property.
My JavaScript Code:
this.add = function()
{
console.log("add");
this.container.appendChild(this.backImg);
this.container.appendChild(this.frontImg);
this.container.className = "card";
document.body.appendChild(this.container);
};
};
var card1 = new Card(1);
card1.add();

Apply the same width and height of the images to the container card, that way:
.card { position: relative; width:150px; height:160px }

Related

Remove elements from array on click in js?

I have an interface [ref below image] where whenever user clicked on close button Image needs to disappear from interface as well as from the array as images are stored in array but currently it is disappeared from front-end interface not from the array.
How will I delete element from interface and removed from array together ?
//a list of img urls needed to feed the list of pictures with some
const images = ['https://www.w3schools.com/css/img_5terre.jpg', 'https://www.w3schools.com/css/img_forest.jpg', 'https://www.w3schools.com/css/img_lights.jpg', 'https://www.w3schools.com/css/img_mountains.jpg'];
//inits the imageList with pictures coming from images constant
//..so when the document is ready,
$(document).ready(() => {
//for each url picture in the images constant
images.forEach((o, i) => {
//append a picture to imageList having that url
appendImageToList(o);
});
});
//appends an image to the list (where image is a picture url)
function appendImageToList(image) {
var img = document.createElement("img");
img.src = image;
//the img will be enclosed in a container
let container = $('<div>', {
class: 'imgContainer'
});
container.append(img);
//creates the close handle for this new picture and adds an event handler on its click event
let closeHandle = $('<div>', {
class: 'closeHandle'
});
//adds content x to the close handle
closeHandle.append('<i class="fa-solid fa-circle-xmark"></i>');
closeHandle.click(() => {
//when the button is clicked, remove this image from the list
removeOneImageFromList($(event.target).closest('.imgContainer'));
});
container.append(closeHandle);
//adds the container inside the imageList
$('#imageList').prepend(container);
}
//removes all images from the list
function removeAllImages() {
$('#imageList .imgContainer').remove();
}
//removes a specific image from the list
function removeOneImageFromList(imgParentElement) {
$(imgParentElement).remove();
}
/* rule to style every single img container */
#imageList .imgContainer {
position: relative;
width: fit-content;
}
/* rule to style the close handle */
#imageList .closeHandle {
position: absolute;
top: 15px;
right: 15px;
text-align: center;
cursor: pointer;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-3.6.0.slim.js"></script>
<button type="button" onclick="removeAllImages();">Remove all images</button>
<br><br>
<div id="imageList">
</div>
Modify your removeOneImageFromList to also use Array.splice to remove the element that matches the src of the image contained in the container that is being removed. You should also modify removeAllImages to empty the list.
//removes all images from the list
function removeAllImages() {
images = []
$('#imageList .imgContainer').remove();
}
//removes a specific image from the list
function removeOneImageFromList(imgParentElement) {
images.splice(images.indexOf($(imgParentElement).find('img').attr('src')), 1)
$(imgParentElement).remove();
}

Setting Max-Height to A Dynamic Table Is Not Working?

I have a table that is generated dynamically using javascript and has rows appended to it using jQuery based on the contents of an array.
My problem is that I want to assign the table a maximum height using the css max-height property so that after a certain height is reached, the table can be scrolled.
This is needed since the table might contain a large number of rows and it would then become too large.
I assigned the table a display: block and a css max-height property of 200px but the property seems to be ignored. The table's height still extends beyond the maximum height set. Is there something I am missing?
Here is a stripped down version of my code that shows what I am want to do. I tried placing the table in a div like kuba suggested but it still doesn't work.
$(document).ready(function() {
$("#mylink").click(function()
{
var jsvCustomIcons = [ "images/img1.png","images/img2.png","images/img3.png","images/img4.png","images/img5.png","images/img6.png" ];
var mydiv = document.createElement("div");
$(mydiv).attr("id","mydiv");
var iconSettingsTable = document.createElement("table");
$(iconSettingsTable).attr("id","iconSettingsTable");
var tempTR,tempDescTH,tempDelTH;
var tempDescTD,tempDelTD,tempImg,tempImg2,tempBold;
tempTR = document.createElement("tr");
$(tempTR).addClass("selectorRowHeader");
tempDescTH = document.createElement("th");
$(tempDescTH).addClass("selectorColHeader");
$(tempDescTH).html("Description");
tempDelTH = document.createElement("th");
$(tempDelTH).addClass("selectorColHeader");
$(tempDelTH).html("Delete");
$(tempTR).append(tempDescTH);
$(tempTR).append(tempDelTH);
$(tempTR).css("background-color","#d3d3d3");
$(iconSettingsTable).append(tempTR);
for(i=0;i<jsvCustomIcons.length;i++)
{
tempTR = document.createElement("tr");
$(tempTR).addClass("selectorRowData");
tempDescTD = document.createElement("td");
$(tempDescTD).addClass("selectorColData");
tempBold = document.createElement("b");
$(tempBold).html(jsvCustomIcons[i]);
$(tempBold).addClass("iconDescriptionTexts");
tempImg2 = document.createElement("img");
$(tempImg2).attr(jsvCustomIcons[i]);
$(tempImg2).addClass("iconDescriptionImages");
$(tempDescTD).append(tempBold);
$(tempDescTD).append(tempImg2);
tempDelTD = document.createElement("td");
$(tempDelTD).addClass("selectorColData");
tempImg = document.createElement("img");
$(tempImg).attr("id","delImage" + i);
$(tempImg).attr("src","images/delete.png");
$(tempImg).css("margin-top","5px");
$(tempImg).click(function()
{
// Code to handle clicks
});
$(tempDelTD).append(tempImg);
$(tempTR).append(tempDescTD);
$(tempTR).append(tempDelTD);
$(iconSettingsTable).append(tempTR);
}
$(iconSettingsTable).css({"position":"absolute","top":$("#iconSettingsSpan").position().top + 20,"left":0});
$(mydiv).append(iconSettingsTable);
$("body").append(mydiv);
});
});
#mydiv {
max-height: 200px;
overflow-y: scroll;
}
#iconSettingsTable {
border: 2px solid black;
}
.selectorColData {
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<span id='iconSettingsSpan'>
<a class='link' style='cursor:pointer;' id='mylink' >Click for Icon Table</a>
</span>
Line 62 of the JavaScript change to position:auto https://jsfiddle.net/tonytansley/dmu5wrd0/
$(iconSettingsTable).css({"position":"auto","top":$("#iconSettingsSpan").position().top + 20,"left":0});
Its because of the "position: absolute" property of that table
Remove that from jquery code (line no 62 )
or use this
#iconSettingsTable
{
border: 2px solid black;
position : static !important;
}
or use this
#mydiv
{
max-height:100px;
overflow-y:scroll;
position : relative;
}
As an update, it seems that if I set the div's position to absolute, it works. My problem was that I was setting the table's position to absolute. Here is an updated jsfiddle:
Link: http://jsfiddle.net/e6gayjps/5/
First, it's important to note that setting max-height directly to the table is unreliable:
In CSS 2.1, the effect of 'min-height' and 'max-height' on tables,
inline tables, table cells, table rows, and row groups is undefined.
Therefore, as you already did, the solution is setting it to a non-tabular parent.
But there is a problem with your approach: your table has position: absolute, so it's taken out of the flow, and thus the height of the parent div is 0. And even if you set an explicit height to it, overflow: scroll won't work, because
['overflow'] affects the clipping of all of the element's content
except any descendant elements (and their respective content and
descendants) whose containing block is the viewport or an ancestor of
the element.
In your case, since the table is positioned its containing block isn't the parent div:
If the element has 'position: absolute', the containing block is
established by the nearest ancestor with a 'position' of 'absolute',
'relative' or 'fixed'
Therefore, to make it work you need to remove table's position: absolute, or set a position different than static to the parent div.

Why are "fadeIn" and "fadeOut" functions moving my divs?

I'm starting a new website and I'm using JQuery for display a div inside another (a title). I have 4 divs displayed inline-block and my result need to be like this :
I'm using Jquery for display the div containing "Accueil" with the function fadeIn and fadeOut but my problem is the following : When the move is over a div, the hidden div is animated and fade in like desired but the other div (on the right) is moving down !
My html is the following :
The left box :
<div class="box-interactive box-interactive1">
<div class="contenu-box">
titi 1
</div>
<div id="bandeau1" class="bandeau">
rr
</div>
</div>
The right box :
<div class="box-interactive box-interactive2">
<div class="contenu-box">
titi 2
</div>
<div id="bandeau2" class="bandeau" style="display : block;">
accueil 2
</div>
</div>
My css :
/*CSS for boxes and interactive text*/
.box-interactive {
width: 300px;
height: 200px;
background-color: red;
margin: 20px;
display: inline-block;
size: fixed;
}
.contenu-box{
width: 300px;
height: 160px;
}
.bandeau {
width: 300px;
height: 40px;
background-image: url("../../img/Alex/accueil.png");
background-size: auto 100%;
position: relative;
display: none;
}
And my JS :
$(function(){
$("div[class^='box-interactive']").hover(
function(){
var id = new Array;
id = $(this).attr('class').split(' ');
for (var i in id) {
if(id[i].match('box-interactive.+')){
var idnum = 'bandeau'+id[i].substring(15);
$("#"+idnum+"").fadeIn(800);
}
}
},
function(){
var id = new Array;
id = $(this).attr('class').split(' ');
for (var i in id) {
if(id[i].match('box-interactive.+')){
var idnum = 'bandeau'+id[i].substring(15);
$("#"+idnum+"").fadeOut(500);
}
}
}
);
});
The second div (it works in both ways) is moving down with specificities : the top of the moving div is equal to the bottom of the first div (the one befor the hidden). Do you have an explaination ?
Fiddle : http://jsfiddle.net/Msh2T/1/ open large the right window to see the problem ;) thx
fadeIn and fadeOut will set an element to "display: none" once the animation completes, removing it from the layout. If you don't want the animation to affect the layout, animate the opacity.
$("#"+idnum+"").animate({opacity: 0}, 800);
...
$("#"+idnum+"").animate({opacity: 1}, 800);
You can float the .bandeau divs so that they aren't affecting the inline layout flow, effectively limiting their scope to the parent div.
.bandeau {
width: 300px;
height: 40px;
background-image: url("../../img/Alex/accueil.png");
background-size: auto 100%;
position: relative;
display: none;
float: left; /* ADD THIS */
}
Fiddle: http://jsfiddle.net/Msh2T/3/
One option would be to animate the opacity either to 1 or to 0 instead of using fadeIn and fadeOut:
$("#"+idnum+"").animate( { opacity:1 }, 800 );
and
$("#"+idnum+"").animate( { opacity:0 }, 500 );
Here's a working fiddle to demonstrate this approach.
A few other notes about the code...
First, your hover-in and hover-out functions are nearly identical. Any time you have that much code that is so similar, it's a very good idea to combine it into a single function.
Where you have this code:
var id = new Array;
id = $(this).attr('class').split(' ');
it's unnecessary to have the new Array, since you are just replacing the value in the next line. Also, I recommend using a plural name for an array instead of a singular name:
var ids = $(this).attr('class').split(' ');
The next line is:
for (var i in id) {
Never use a 'for..in' loop on an array. It will bite you if anyone ever augments Array.prototype with new methods or properties. Instead, use a numeric for loop or an iterator such as jQuery's $.each().
Next is this code:
if(ids[i].match('box-interactive.+')){
var idnum = 'bandeau'+id[i].substring(15);
...
When you use .match to test a string like this, you can also use it to extract the part of the string you want, without resorting to a brittle-to-maintain .substring(15) call:
var match = ids[i].match( /box-interactive(.+)/ );
if( match ) {
var idnum = 'bandeau' + match[1];
...
Now having said all this, why not simplify things much further and let jQuery do all the work for you? There's no need for any of this fancy array looping and checking of classnames. You can replace the entire JavaScript code with this:
$(function(){
$("div[class^='box-interactive']").hover(
function(){
$(this).find('.bandeau').animate( { opacity:1 }, 800 );
},
function(){
$(this).find('.bandeau').animate( { opacity:0 }, 500 );
}
);
});
Updated fiddle
(You may note that I've contradicted my first piece of advice here and didn't combine the bit of duplicate code in the hover-in and hover-out functions. But there's now so little code that that the duplication isn't worth worrying about.)
Try using z-index in your CSS to stack your divs on top of each other

Child Div styles in javascript

I have got a preview box that gets the color and then changes it when the user does. However i have a child div that needs changine. how can i select the child div through get element by id?
this is the java script i have at the moment, how do i change this so i can get the child div front to change color
document.getElementById("flip3D").style.backgroundColor=p1;
#flip3D{
width:200px;
height:200px;
margin:20px;
float:left;
}
#flip3D > .front{
... style stuff is all there just to much toput in and worry about
}
You mean something like this?
var front = document.querySelectorAll('#flip3D .front');
for(var i=0; i<front.length; i++){
front[i].style.backgroundColor = 'red';
}
or like:
var flipEl = document.getElementById("flip3D");
var frontEl = flipEl.getElementsByClassName('front');
for(var i=0; i<frontEl.length; i++){
frontEl[i].style.backgroundColor = p1;
}
Why not do it using CSS? (Your Question is pretty unclear so my hands are tied)
You could go with .childNodes() and .children() (Google will give you a lot of learning resources for these two methods. )
They will aid in selecting child elements within the DOM, of a specific element.
My first suggestion would be to use jQuery for this type of manipulation. It makes navigating the DOM and changing attributes much easier.
My second suggestion would be to control the color of both elements with a class. So your CSS might look something like this:
#flip3D{
width:200px;
height:200px;
margin:20px;
float:left;
background: /*whatever you want the initial color to be*/;
}
#flip3D > .front {
/*Initial styling*/
}
#flip3D.stateChanged{
background: /*Whatever you want the new color to be*/;
}
#flip3D.stateChanged > .front {
/*New styling*/
}
Then in your Javascript you would change the class like this:
jQuery Example (using toggleClass):
jQuery('#flip3D').toggleClass('stateChanged');
You can also do the class manipulation in vanilla javascript but it is much messier. Something like this:
var ele = document.getElementById('#flip3D');
if(ele.className == 'stateChanged')
ele.className = '';
else
ele.className = 'stateChanged';
The simpleste way to do this is by using CSS. Change the background-color to inherit, that way they will allways have the color of their parent.
.child-node {
background-color: inherit;
}

Need to find height of hidden div on page (set to display:none)

I need to measure the offsetHeight of a div that is inside of a hidden element.
<div id="parent" style="display: none;">
<div id="child">Lorem Ipsum dolor sit amet.</div>
</div>
The parent div must be set to "display:none". I have no control over that. I realize that the offsetHeight of the child div is going to be 0. I need to find a workaround.
Something I've toyed with is when the page loads, I copy the childnodes of parent, inject in a div on the page that is set to "visiblity:hidden". Then I measure the height of those elements, and remove the nodes when done.
Any other thoughts?
Update:
What I wound up having to do was this:
Using YUI 2, on page load, I found all elements of that given classname that were either set to display:none, or whose height and width was 0 (that's one way of measuring whether an element exists, or a parent is set to display:none). I then set that element to display:block. I then checked it's parent for the same thing and showed the parents until it finds a visible parent. Once highest display:none ancestor is set to display:block, I can measure my element.
Once all elements are measured I reset all of the elements back to display:none.
You need to make element's parent visible for that one very short moment while you're getting element's dimensions. In a generic solution, all ancestors are usually traversed and are made visible. Then their display values are set back to original ones.
There are performance concerns of course.
We considered this approach in Prototype.js implementation but ended up with getWidth and getHeight making only actual element visible, without traversing ancestors.
The problem with alternative solutions - such as taking element out of "hidden" parent - is that certain styles might no longer apply to an element once it's out of its "regular" hierarchy. If you have a structure like this:
<div class="foo" style="display:none;">
<div class="bar">...</div>
</div>
and these rules:
.bar { width: 10em; }
.foo .bar { width: 15em; }
then taking element out of its parent will actually result in wrong dimensions.
If you use style.display = "none", the element will have 0 width and height,
but using the style.visibility = "hidden" instead, the element will have the width and height calculated by the browser (as normally).
A workaround is to set the height to 0
.hidden {
height: 0;
overflow: hidden;
}
Then to get the elements scrollHeight.
document.querySelector('.hidden').scrollHeight
The scrollHeight will correctly give you the height though the element does not appear. I don't think it affects element flow either.
Example: https://jsfiddle.net/de3vk8p4/7/
Reference: https://developer.mozilla.org/en-US/docs/Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements#How_big_is_the_content.3F
You could clone the element, absolutely position it at -10000,-10000, measure the clone and destroy it.
Made a pure js solution with no Jquery and with no cloning (which I guess is faster)
var getHeight = function(el) {
var el_style = window.getComputedStyle(el),
el_display = el_style.display,
el_position = el_style.position,
el_visibility = el_style.visibility,
el_max_height = el_style.maxHeight.replace('px', '').replace('%', ''),
wanted_height = 0;
// if its not hidden we just return normal height
if(el_display !== 'none' && el_max_height !== '0') {
return el.offsetHeight;
}
// the element is hidden so:
// making the el block so we can meassure its height but still be hidden
el.style.position = 'absolute';
el.style.visibility = 'hidden';
el.style.display = 'block';
wanted_height = el.offsetHeight;
// reverting to the original values
el.style.display = el_display;
el.style.position = el_position;
el.style.visibility = el_visibility;
return wanted_height;
}
here is the demo
https://jsfiddle.net/xuumzf9k/1/
Please let me know if you can find any improvements to this (as I use this in my main projects)
So here's working jQuery solution based on lod3n's answer and with help of 999's comment:
var getHiddenElementHeight = function(element){
var tempId = 'tmp-'+Math.floor(Math.random()*99999);//generating unique id just in case
$(element).clone()
.css('position','absolute')
.css('height','auto').css('width','1000px')
//inject right into parent element so all the css applies (yes, i know, except the :first-child and other pseudo stuff..
.appendTo($(element).parent())
.css('left','-10000em')
.addClass(tempId).show()
h = $('.'+tempId).height()
$('.'+tempId).remove()
return h;
}
Enjoy!
A helper function ---
function getElementHeight(el) {
var clone = el.cloneNode(true);
var width = el.getBoundingClientRect().width;
clone.style.cssText = 'position: fixed; top: 0; left: 0; overflow: auto; visibility: hidden; pointer-events: none; height: unset; max-height: unset; width: ' + width + 'px';
document.body.append(clone);
var height = clone.getBoundingClientRect().height + 'px';
clone.remove();
return height;
}
Creates a clone, appends it to the DOM (hidden), takes the height, then removes it.
Position of fixed and the top/left are in case your app allows scrolling at the body-level - it attempts to prevent a scrollbar rave party - can remove if you handle scrolling in children elements.
Overflow, height, and max-height settings to attempt to 'reset' height settings and let it be it's natural height on the clone.
Visibility for the obvious and pointer-events as a 'just in case' the rendering of the element takes a while and don't want to interrupt user-input.
An example having an 'accordion-like' animated open/close allowing for dynamic heights.
function getElementHeight(el) {
var clone = el.cloneNode(true);
clone.style.cssText = 'position: fixed; top: 0; left: 0; overflow: auto; visibility: hidden; pointer-events: none; height: unset; max-height: unset';
document.body.append(clone);
var height = clone.getBoundingClientRect().height + 'px';
clone.remove();
return height;
}
var expanded = false;
var timeout;
function toggle() {
var el = document.getElementById('example');
expanded = !expanded;
if (expanded) {
el.style.maxHeight = getElementHeight(el);
// Remove max-height setting to allow dynamic height after it's shown
clearTimeout(timeout);
var openTimeout = timeout = setTimeout(function() {
el.style.maxHeight = 'unset';
clearTimeout(openTimeout);
}, 1000); // Match transition
} else {
// Set max height to current height for something to animate from
el.style.maxHeight = getElementHeight(el);
// Let DOM element update max-height, then set to 0 for animated close
clearTimeout(timeout);
var closeTimeout = timeout = setTimeout(function() {
el.style.maxHeight = 0;
clearTimeout(closeTimeout);
}, 1);
}
}
#example {
overflow: hidden;
max-height: 0;
transition: max-height 1s;
}
<button onclick="toggle()">Toggle</button>
<div id="example">
<textarea>Resize me</textarea>
</div>
In the JS please use 'scrollHeight'
Example Code
Assume that this div is hidden in DOM
<div class="test-div">
//Some contents
<div>
Javascript to find this div height
const testHeight = document.querySelector('.test-div');
testHeight.scrollHeight
Use z-index to hide element under non-transparent element, show it, and get height.
Until the element is rendered, it has no height. Even if you clone the parent object and display it somewhere that can't be seen by the user, there's not guarantee that the clone will have the same height as the final size of the hidden object.
There are many things that can affect the height that wouldn't necessarily be rendered in the clone - anything in the DOM and its interaction with the CSS rules could cause a change in rendering any other element of the DOM. Short of cloning the entire document (and even that's not fool-proof) you have no way of determining the height of the hidden object.
If you must know the height before it's displayed to the user, you'll have to "hack" it by displaying it for as short of a time as possible then hiding it again. Most likely, the user will see this hiccup and not be pleased by the result.
So, you cannot even change the display:none; to height:0; overflow:hidden; ? Maybe you could override that in your own stylesheet like so:
div#parent { display: block !important; height:0; overflow:hidden; }
And then as you are using YUI (assuming YUI 2) you could use this:
var region = YAHOO.util.Dom.getRegion('child');
To get the dimensions and offset of the child.
Try to use:
#parent{ display:block !important; visibility:hidden; position:absolute}
What I wound up having to do was this:
Using YUI 2, on page load, I found all elements of that given classname that were either set to display:none, or whose height and width was 0 (that's one way of measuring whether an element exists, or a parent is set to display:none). I then set that element to display:block. I then checked it's parent for the same thing and showed the parents until it finds a visible parent. Once highest display:none ancestor is set to display:block, I can measure my element.
Once all elements are measured I reset all of the elements back to display:none.
Did you try this ?
setTimeout('alert($(".Var").height());',200);

Categories