How to impose CSS changes to related sibling element? - javascript

Basically I have multiple parent div with pairs of button and div child elements.
What I want to do is impose changes to the "related" div when a button is clicked. So if Button 2 is clicked, the changes should be imposed on toast 2.
My issue is that no matter the button clicked it's only the first occurrence that is changed.
In my example I set the click to change the display value of the relevant element as an example, but in reality any CSS change should be possible.
Here is a link to a complete and functional codepen as well.
function hide() {
var element = document.querySelector('.toast');
element.style.display = (element.style.display == 'none') ? 'block' : 'none';
}
.parent {
position : relative;
display : inline-block;
height : 55px;
}
button#button {
width : 100px;
height : 35px;
}
.toast {
display : block;
position : absolute;
top : 40px;
background-color : black;
}
<div class="parent">
<button id="button" onclick="hide()">Button 1</button>
<div class="toast">A box with text</div>
</div>
<div class="parent">
<button id="button" onclick="hide()">Button 2</button>
<div class="toast">A box with text</div>
</div>
<div class="parent">
<button id="button" onclick="hide()">Etc...</button>
<div class="toast">A box with text</div>
</div>

Don't duplicate IDs
Avoid using onclick attributes. They have a number of drawbacks and addEventListener makes this easier.
Pay attention to the event object that is passed to your listener. It will tell you where the click was.
Navigate up (using closest) and down (using querySelector) the DOM from that element
function hide(event) {
// We're using event delegation so if the click isn't from a button we stop immediately
if (!event.target.matches(".parent button")) {
return false;
}
// Seach from the button up until we find the parent
const parent = event.target.closest(".parent");
// Search down from the parent until we find the toast
const toast = parent.querySelector('.toast');
toast.style.display = (toast.style.display == 'none') ? 'block' : 'none';
}
addEventListener('click', hide);
.parent {
position: relative;
display: inline-block;
height: 55px;
}
.parent button {
width: 100px;
height: 35px;
}
.toast {
display: block;
position: absolute;
top: 40px;
background-color: black;
}
<div class="parent">
<button>Button 1</button>
<div class="toast">A box with text</div>
</div>
<div class="parent">
<button>Button 2</button>
<div class="toast">A box with text</div>
</div>
<div class="parent">
<button>Etc...</button>
<div class="toast">A box with text</div>
</div>

Related

Horizontal scrolling of div not working with scrollLeft

I tried to make horizontal scrolling with scrollLeft. I'm able to align div horizontally but it looks like the scrollLeft function is not working.
Here is my code:
function myFunction() {
var elmnt = document.getElementById("myDIV");
elmnt.scrollLeft += 50;
}
#myDIV {
height: 250px;
width: auto;
display:inline-flex;
gap:10px;
overflow: auto;
}
#content {
height: 800px;
width: 200px;
background-color: coral;
}
<button onclick="myFunction()">Scroll div</button><br><br>
<div id="myDIV">
<div id="content">
Some text inside a div element.<br><br>
Some text inside a div element.
</div>
<div id="content">
Some text inside a div element.<br><br>
Some text inside a div element.
</div>
<div id="content">
Some text inside a div element.<br><br>
Some text inside a div element.
</div>
<div id="content">
Some text inside a div element.<br><br>
Some text inside a div element.
</div>
<div id="content">
Some text inside a div element.<br><br>
Some text inside a div element.
</div>
</div>
I applied the white-space and overflow style inside the #myDiv style; I set the width property to 220px to follow the scrollLeft[1].
function myFunction() {
var element = document.getElementById("myDIV");
element.scrollLeft += 50;
}
#myDIV {
white-space: nowrap;
overflow: scroll;
width: 220px;
height: 250px;
display: inline-flex;
gap: 10px;
}
#content {
height: 800px;
width: 200px;
background-color: coral;
}
<button onclick="myFunction()">Scroll div</button><br><br>
<div id="myDIV">
<div id="content">
Some text inside a div element.<br><br>
Some text inside a div element.
</div>
<div id="content">
Some text inside a div element.<br><br>
Some text inside a div element.
</div>
<div id="content">
Some text inside a div element.<br><br>
Some text inside a div element.
</div>
<div id="content">
Some text inside a div element.<br><br>
Some text inside a div element.
</div>
<div id="content">
Some text inside a div element.<br><br>
Some text inside a div element.
</div>
</div>
1 - JavaScript element.scrollLeft not working

.child element with class selected should be on top of other .child elements, each .child is inside .parent element with absolute position

Given the html and css below, is it possible to have a .child with class selected appear on top of other .child elements? I'd like if you can give an answer that would not change html structure and css position property of .child and .parent.
Also would be great to not toggle anything on parent, it is better to toggle child classes or styles, for parent it is better to set it once.
.parent {
position: absolute;
}
.child {
position: relative;
}
<div>
<div>
<div class="parent">
<div class="child selected"></div>
</div>
<div class="parent">
<div class="child"></div>
</div>
</div>
</div>
Greatly appreciate any input, thank you.
If you really want to stick to this HTML structure you could as example hide all elements (children) and show them only when they are selected.
A better solution would be having the selected class on the parent so then you could just simply give the selected parent a higher z-index.
Here you can find a snippet of how you can toggle the display without touching the HTML
// for demo purpuses
var toggleLayer = function() {
var next = $('.child.selected').removeClass('selected').closest('.parent').next();
var element = next.length ? next : $('.parent:first-child');
element.find('.child').addClass('selected')
}
.parent {
position: absolute;
}
.child {
position: relative;
display: none;
}
.selected {
display: block;
}
/* for demo purpuses */
.child {
height: 100px;
width: 100px;
line-height: 100px;
text-align: center;
background: red;
}
button {
position: fixed;
top: 120px;
left: 10px;
}
<div>
<div>
<div class="parent">
<div class="child selected">1</div>
</div>
<div class="parent">
<div class="child">2</div>
</div>
<div class="parent">
<div class="child">3</div>
</div>
<div class="parent">
<div class="child">4</div>
</div>
</div>
</div>
<!--- FOR DEMO PURPUSES --->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button onClick="toggleLayer()">Toggle layer</button>

Rewrite Show/Hide Multiple Divs form JQ to clear JS

I wrote script in JQuery but I want to write in clear JS.
I can fix my problem if I m going to use onclick event in HTML code for example:
var divs = ["Div1", "Div2", "Div3", "Div4"];
var visibleDivId = null;
function divVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
.buttons a {
font-size: 16px;
}
.buttons a:hover {
cursor:pointer;
font-s
<div class="main_div">
<div class="buttons">
Div1 |
Div2 |
Div3 |
Div4
</div>
<div class="inner_div">
<div id="Div1">I'm Div One</div>
<div id="Div2" style="display: none;">I'm Div Two</div>
<div id="Div3" style="display: none;">I'm Div Three</div>
<div id="Div4" style="display: none;">I'm Div Four</div>
</div>
</div>
But I don't want to mix HTML with JS, and I want to use addEventListener.
My JQ Code below
jQuery(function(){
$('.targetDiv').hide();
jQuery('#showall').click(function(){
jQuery('.targetDiv').toggle();
});
jQuery('.showSingle').click(function(){
jQuery('#div'+$(this).attr('target')).toggle();
});
});
.showSingle{
padding: .9em;
margin: .2em;
border: 1px solid black;
float: left;
}
#showall{
padding: .9em;
margin: .2em;
border: 1px solid black;
float: left;
}
.cnt{
margin-top: 2em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="menu">
<a id="showall">All</a>
<a class="showSingle" target="1">Div 1</a>
<a class="showSingle" target="2">Div 2</a>
<a class="showSingle" target="3">Div 3</a>
<a class="showSingle" target="4">Div 4</a>
</div>
<section class="cnt">
<div id="div1" class="targetDiv">Content 1</div>
<div id="div2" class="targetDiv">Content 2</div>
<div id="div3" class="targetDiv">Content 3</div>
<div id="div4" class="targetDiv">Content 4</div>
</section>
I was trying make problem but every solution was failed, I will very thankful for help
So, all the HTML event attributes (onclick) come out and are replaced by DOM object references that hook up event callbacks with .addEventListener().
Since you have dedicated <a> elements in their own parent that show one of a set of dedicated <div> elements within their own parent. We can simply use the index of the clicked <a> as the index of the <div> that needs to be shown.
As for CSS, you should also not use individual styles, but rather just apply or remove a class. This is much simpler and more flexible.
// Get all the <a> elements that will trigger the show/hide code
var anchors = document.querySelectorAll(".buttons > a.showSingle");
// Convert anchors to a proper Array (so .forEach() and other Array methods work)
var anchorsArray = Array.prototype.slice.call(anchors);
// Set up each anchor with a click event handler
anchorsArray.forEach(function(a){
a.addEventListener("click", showHideDiv);
});
// Get reference to the "show all" anchor
var showAll = document.getElementById("showall");
// Set up click event handler for that single anchor
showAll.addEventListener("click", showAllDivs);
// Get all the <div> elements that will need to be shown or hidden
var divs = document.querySelectorAll(".inner_div > div[id^='div']");
// Convert divs to proper array (so .forEach() and other Array methods work)
var divArray = Array.prototype.slice.call(divs);
function showHideDiv(evt) {
// Cancel the link's native click behavior
evt.preventDefault();
evt.stopPropagation();
// Hide all the divs
divArray.forEach(function(d){
// No need to mess with individual style properties. Just apply a pre-existing class
d.classList.add("hidden");
});
// Show the div that was clicked using the index of the anchor
// By removing the "hide" class, the element's style goes back to
// whatever it was without that class.
divs[anchorsArray.indexOf(evt.target)].classList.remove("hidden");
}
function showAllDivs(){
// Show all the divs
divArray.forEach(function(d){
// No need to mess with individual style properties. Just apply a pre-existing class
d.classList.remove("hidden");
});
}
.buttons a {
font-size: 16px;
background-color:#aaf;
transition: .5s;
}
.buttons a:hover {
cursor:pointer;
background-color:#66f;
font-size: 18px;
}
/* This class will either be applied or not to take care of the visibility */
.hidden {
display:none;
}
.showSingle{
padding: .9em;
margin: .2em;
border: 1px solid black;
float: left;
}
#showall{
padding: .9em;
margin: .2em;
border: 1px solid black;
float: left;
}
.cnt{
margin-top: 2em;
}
<div class="main_div">
<div class="buttons">
<a id="showall">All</a>
<a class="showSingle">Div 1</a>
<a class="showSingle">Div 2</a>
<a class="showSingle">Div 3</a>
<a class="showSingle">Div 4</a>
</div>
<section class="cnt">
<div class="inner_div">
<div id="div1">I'm Div One</div>
<div id="div2" class="hidden">I'm Div Two</div>
<div id="div3" class="hidden">I'm Div Three</div>
<div id="div4" class="hidden">I'm Div Four</div>
</div>
</section>
</div>

onmouseover eventlistener onto all children

I have a problem with the onmouseover() event listener.
<div class="parent" onmouseover="myfunction()">
<div class="child"></div>
</div>
I trigger a javascript function whenever the mouse is hovering over the parrent, but whenever I'm hovering over the child, it doesn't register the onmouseover anymore.
Is there a workaround so the onmouseover() also gets triggered while hovering over its child elements, using pure Javascript?
Use mouseenter event instead, which doesn't bubble with children elements like mouseoverdoes.
In other words with mouseover the event will be attached to all the element children too, so when you hover a child the event will be fired as if we left the parent div.
Demo:
document.getElementById("test").addEventListener("mouseenter", function(event) {
var target = event.target;
console.log(target.id);
}, false);
.child {
min-width: 50px;
min-height: 50px;
padding: 10px;
display: inline-block;
background-color: yellow;
}
.parent {
padding: 20px;
background-color: red;
}
<div id="test" class="parent">
<div id="child1" class="child">1</div>
<div id="child2" class="child">2</div>
<div id="child3" class="child">3</div>
<div id="child4" class="child">4</div>
<div id="child4" class="child">5</div>
</div>
You can see in the above snippet that using mouseenter the event is always firing even if we hover over children and only the parent id is logged, as if we didn't leave it.
Mouseover demo:
You can see the difference here using mouseover event:
document.querySelector(".parent").addEventListener("mouseover", function(event){
console.log(event.target.id);
});
.child {
min-width: 50px;
min-height: 50px;
padding: 10px;
display: inline-block;
background-color: yellow;
}
.parent {
padding: 20px;
background-color: red;
}
<div class="parent">
<div id="child1" class="child">1</div>
<div id="child2" class="child">2</div>
<div id="child3" class="child">3</div>
<div id="child4" class="child">4</div>
<div id="child4" class="child">5</div>
</div>

hiding div after another is clicked

I want to hide the current div that's displayed using .toggle when another is clicked.
When another div is toggled by clicking on another link in .left, I want the div that's currently displayed in .right to disappear and be replaced with the one that's clicked. Currently div's that have been toggled stay there until toggled off onclick, I want the toggle off to trigger when another div is selected from .left
Tried using .hide and an if statement, but couldn't seem to get the JS to function properly. If someone could just point me in the right direction that would be great.
Apologies if I've phrased this badly (new to SO). Happy to edit accordingly.
JS fiddle
HTML:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<div class="wrap">
<div class="left">
<div class="row">
<div class="links">
When this link is clicked, i want the first div to be shown
When this link is clicked, i want the second div to be shown
When this link is clicked, i want the third div to be shown
When this link is clicked, i want the fourth div to be shown
</div>
</div>
</div>
<!--left-->
<div class="right">
<div class="row">
<div>Content to be shown when the first link is clicked</div>
<div>Content to be shown when the second link is clicked</div>
<div>Content to be shown when the third link is clicked</div>
<div>Content to be shown when the fourth link is clicked</div>
</div>
</div>
<!--right-->
</div><!--wrap-->
CSS:
.links a {
display: block;
}
.row > div:not(.links) {
display: none;
}
.wrap {
width: 1000px;
height: 1000px;
}
.left {
width: 500px;
height: 1000px;
float: left;
display: inline;
}
.right {
width: 500px;
height: 1000px;
float: right;
display: inline;
}
.links a {
width: 490px;
}
.links {
margin-top: 20px;
}
JS:
var links = $('.links a');
links.on('click', function() {
var n = links.index(this);
$('.row > div:not(.links)').eq(n).toggle();
});
Add the following to your code inside the function
$('.row > div:not(.links)').hide();
Here is JS fiddle
Check out this i little edit your code see live demo at https://jsfiddle.net/7xt1d887/ Hope it will help You :)
ADD this
$('.right .row').find('div').hide();

Categories