I need help toggling overlays with multiple divs. I don't want to have a separate function for each one (there's 6 with 6 different overlay popups). The onclick div will reveal the overlay popup. Help is appreciated!
I need help toggling overlays with multiple divs. I don't want to have a separate function for each one (there's 6 with 6 different overlay popups). The onclick div will reveal the overlay popup. Help is appreciated!
function on() {
document.getElementById("overlay").style.display = "block";
}
function off() {
document.getElementById("overlay").style.display = "none";
}
#overlay {
position: fixed;
display: none;
width: 100%;
height: 100%;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0,0,0,0.8);
z-index: 2;
cursor: pointer;
}
#text{
position: absolute;
top: 50%;
left: 50%;
font-size: 1rem;
color: white;
transform: translate(-50%,-50%);
-ms-transform: translate(-50%,-50%);
}
<!-- //DIV -->
<div class="row ">
<div class="col-md-6 col-lg-4 d-flex align-items-stretch" onclick="on()">
<div class="card mb-3">
<img src="img/ballet.jpg" class="embed-responsive w-100 classpic" alt="...">
<div class="card-body">
<h5 class="card-title">BALLET</h5>
</div>
</div>
</div>
<!-- //POPUP -->
<div id="overlay" onclick="off()">
<div id="text">
<h3>Ballet</h3>
<p>Ballet is an artistic dance form performed to music using precise and highly formalized set steps and gestures.
Classical ballet, which originated in Renaissance Italy and established its present form during the 19th century,
is characterized by light, graceful, fluid movements and the use of pointe shoes.
</p>
<h4>Shedule:</h4>
<p>Ages 4-8: Thursdays • 4PM<br>
Ages 9-14: Fridays • 7PM</p>
</div>
</div>
There's a problem with your approach, namely, when an element has display:none it is removed from the html tree and cannot receive a click event. Also, no two elements can share the same id attribute and so your function cannot be applied by reference to an id directly.
I've made a working snippet that achieves what I think you are after. There are undoubtedly others that would work but it's quite straight forward and works.
Firstly, arrange each of your alternative div pairs (one hidden, one visible) inside a parent div and give it a class name. This has the advantage that, if you size the container div appropriately, the content will not jump about when you swap the hidden div for visible and vice versa. Next, give classes to distinguish the (initially) hidden content from the visible div. Your markup pattern then will be repeats of:
<div class='container'>
<div class='main'>my first main content</div>
<div class='hidden'>my first hidden content </div>
</div>
In the style sheet, set the class display properties:
.hidden {
display: none;
}
.main {
display: block;
}
Then, set up a click event listener in javascript. This will take a click event from anywhere on the page.
document.addEventListener('click', event => {
})
inside the event listener, place an if block to test whether the click event was received by an element that was inside a div of .container class:
if (event.target.parentElement.className=='container') {
}
I slightly modified this, see edit note and bottom.
If the click event got that far, the click must have been recieved by the visible div inside that container (since the hidden one cannot receive click events and they are the only two elements present.
So you can go ahead and swap the classes applied to the visible div that received the click:
event.target.classList.add('hidden');
event.target.classList.remove('main');
You now have to do the opposite to the other div in the container class to make that sibling visible. The problem is, you don't know whether the hidden class was the first child, or the second child of the container div. What you do know for sure, is that the other div is a sibling of the div you just made invisible.
So we can test to see if there is a next sibling using a conditional:
if (event.target.nextElementSibling) {
event.target.nextElementSibling.classList.add('main');
event.target.nextElementSibling.classList.remove('hidden');
}
If the hidden div followed the visible one, a nextElementSibling will be found and the classes swapped. If no nextElementSibling was found, we know the other div had to come before the one we already hid.
so, an else extension of that if block can be added to switch the classes on the previousElementSibling:
...} else {
event.target.previousElementSibling.classList.add('main');
event.target.previousElementSibling.classList.remove('hidden');
} // end else;
And you're done!
I wanted to explain the logic in detail to make sure you know what's going on, but it's not that complicated.
The advantage of an approach like this is that the single event listener will cope with 1, 2, or 1,000 pairs of divs and none need any special IDs or anything other than an initial class of .main or .hidden (and that they be grouped inside a .container div.
document.addEventListener('click', event => {
if (event.target.parentElement && event.target.parentElement.className=='container') {
event.target.classList.add('hidden');
event.target.classList.remove('main');
if(event.target.nextElementSibling) {
event.target.nextElementSibling.classList.add('main');
event.target.nextElementSibling.classList.remove('hidden');
} else {
event.target.previousElementSibling.classList.add('main');
event.target.previousElementSibling.classList.remove('hidden');
} // end else;
} // end parentElement if;
}) // end click listener;
.hidden {
display: none;
border: 1px solid red;
margin: 5px;
}
.main {
display: block;
border: 1px solid black;
margin: 5px;
}
<div class='container'>
<div class='main'>my first main content</div>
<div class='hidden'>my first hidden content </div>
</div>
<div class='container'>
<div class='main'>my second main content</div>
<div class='hidden'>my second hidden content </div>
</div>
Edit the conditional to detect whether the parent element of the click event was a .container div was modified to check that the event target has a parent AND that the parent is a .container div. This prevents an error if a click is received anywhere outside of the container div.
** Displaying an Opaque Overlay in Response to Click **
Again, this solution allows the functionality to be applied to limitless div elements without the need for independent ids. Again, two classed .main and .hidden are used to decide which div has been clicked from a single event listener applied to the document rather than to multiple divs.
The basic process of displaying, and then re-hiding the (originally hidden) .overlay div is very simple:
if (element.className == 'main') {
element.parentElement.getElementsByClassName('overlay')[0].classList.remove('hidden');
}
if (element.className == 'overlay') {
element.classList.add('hidden');
}
However, a problem arises because of the use of class names, rather than ids. Namely, when the overlay is displayed, a click on it may be received by a descendent element that does not have the class name .hidden. To work properly, every descendent of the overlay div would have to be given the .hidden class and the class swapped applied for ever element inside the .hidden div. This could get very complicated if the div had many child elements (perhaps with their own descendents).
Instead, when a click is received, the target element is inspected to see if it has a relevant class (main or hidden). If it does, the script flows to the simple class switching blocks. If it has no, or a different class name however, a do-while loop examined the parent element of the click to see if it was contained in a relevant (main or hidden) class. The loop continues searching up the document tree until either a relevant element is found, or there are no more parent elements to examine.
If a parent is found to have the required class name, a reference to the element is passed onto the class switching block.
do {
if (element && (element.className == 'overlay' || element.className == 'main')) {
// foundElementClassName = element.className;
break;
} // end if;
if (element.parentElement) {
element = element.parentElement;
} else {
break;
}
} while (element.className != "overlay" || element.className != "main");
The following working snippet demonstrates the functionality. In it, three divs (coloured pink) have an associated (initially) hidden overlay div, while a fourth div has no associated overlay and should ignore clicks.
If a click is made on a pink div, it's specific overlay appears. A click anywhere on the overlay dismisses it, regardless of whether the click was received by the overlay div itself, or by a child element or deeper descendent (e.g. clicking on the text of the overlay (which is in a child h2 element still allows the correct .overlay div to have its styles switched to hide it again.
document.addEventListener('click', (event) => {
let element = event.target;
do {
if (element && (element.className == 'overlay' || element.className == 'main')) {
// foundElementClassName = element.className;
break;
} // end if;
if (element.parentElement) {
element = element.parentElement;
} else {
break;
}
} while (element.className != "overlay" || element.className != "main");
// end do-while loop;
// if a relevant element was found, the element object is stored in element variable;
if (element.className == 'main') {
element.parentElement.getElementsByClassName('overlay')[0].classList.remove('hidden');
}
if (element.className == 'overlay') {
element.classList.add('hidden');
}
}) // end click event listener;
.main {
display: block;
width: 50%;
margin: 10px;
border: 1px solid black;
background: pink;
}
.overlay {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
top: 0px;
left: 0px;
width: 100%;
min-height: 100%;
bottom: auto;
z-index: 1;
background: rgba(255,255,0,0.7);
padding: 20px;
}
.hidden {
display: none;
}
.other {
display: block;
width: 50%;
margin: 10px;
border: 1px solid black;
background: yellow;
}
<div class="container">
<div class="main">Content of div 1. Content of div 1. Content of div 1. Content of div 1. Content of div 1. Content of div 1. Content of div 1. Content of div 1 </div>
<div class="overlay hidden"><h1>overlay for first pink div</h1> </div>
</div>
<div class="other">
some other content that doesn't have an associated overlay and that should ignore clicks.
</div>
<div class="container">
<div class="main">Content of div 2. Content of div 2. Content of div 2. Content of div 2. Content of div 2. Content of div 2. Content of div 2. Content of div 2. Content of div 2. Content of div 2.</div>
<div class="overlay hidden"><h1>overlay for SECOND pink div</h1> </div>
</div>
<div class="container">
<div class="main">Content of div 3. Content of div 3. Content of div 3. Content of div 3. Content of div 3. Content of div 3. Content of div 3. Content of div 3. Content of div 3. Content of div 3. </div>
<div class="overlay hidden"><h1>overlay for Third pink div</h1> </div>
</div>
Related
i started an interactive rating card.
The goal is to choose a number how you would rate and then to submit your answer.
i want to chose a number and then with and eventlistner to change the background of the div element of the choosen number from the current background to another color. So far i have the submit button and recive a thank you message on the card after the button.
this is the html of the 5 number you can choose to rate
<div class="numbers">
<div class="one">1</div>
<div class="two">2</div>
<div class="three">3</div>
<div class="four">4</div>
<div class="five">5</div>
</div>
this is the css for example for the first div. All divs have the same css code
.one {
width: 60px;
height: 60px;
color: var(--text-color);
background-color: var(--background-color-body);
border-radius: 50%;
justify-content: center;
align-items: center;
display: flex;
font-weight: 800;
}
I tried with a for Loop to go through all the numbers and by clicking to change the backgroug color
this was the javascript code i tried
addEventListener('click', myFunction);
{
function myFunction() {
var drugi = document.querySelectorAll('.numbers div');
for (i = 0; i <= element.length; i++) {
element[i].style.backgroundColor = 'white';
}
}
}
There are three problems wit your .js code. First, you have the function myFunction in a different scope than the event listener addEventListener('click', myFunction). So to fix it just remove the keys that wrap it. Second, you are using the element before declaring it. And third, the loop will assign the same color to all the element. (Notice a background color white will be not noticed).
To fix it, just use the event delegation pattern on the parent (which is the div element with the class numbers) and check if the target is a div element with the class number and then change the background color.
const numbers = document.querySelector('.numbers')
numbers.addEventListener('click', () => {
const target = event.target
if (target.className === 'numbers') return
target.style.backgroundColor = 'blue'
})
How would I be able to simplify this jquery code. I feel like I am repeating myself and just wondering if there is a shorter way to write this which I'm sure there is. I am a bit new to javascript and jquery. I have created a two tabs with their own containers with miscellaneous information in them. Basically I want the container to open when it's related tab is clicked on. I also would like the tab to be highlighted when it's active. Also, how would I be able to write code to make all tab containers disappear when you click off from the tab containers.
<!-- HTML Code -->
<div class="sort-filters">
<span class="sort-by active">SORT BY</span>
<span class="filter">FILTER</span>
</div>
<div class="sort-containers">
<div class="sort-by-container">Sort by click me here</div>
<div class="filter-container">Filter click me here</div>
</div>
/* CSS */
.sort-filters {
display: flex;
width: 500px;
height: 30px;
}
.sort-by,
.filter {
background: #CCC;
color: #756661;
flex: 1;
display: flex;
justify-content: center;
align-items: center;
font-family: 'Arial', sans-serif;
cursor: pointer;
}
.sort-by-container,
.filter-container {
width: 500px;
background: #756661;
color: #FFF;
height: 100px;
display: none;
}
.active {
background: #756661;
color: #FFF;
transition: 0.2s;
}
// Jquery Code
js = $.noConflict();
var sort = js('.sort-by');
var filter = js('.filter');
var sortContainer = js('.sort-by-container');
var filterContainer = js('.filter-container');
js(sort).click(function() {
js(filterContainer).hide();
js(sortContainer).show();
js(sort).addClass('active');
js(filter).removeClass('active');
});
js(filter).click(function() {
js(sortContainer).hide();
js(filterContainer).show();
js(filter).addClass('active');
js(sort).removeClass('active');
});
In order to avoid such repetitive actions I like to stick to naming conventions, so that I can apply the ID's, classes or attributes from one element to select other elements, for instance:
<div id="tabs">
<span class="active" data-type="sort-by">SORT BY</span>
<span data-type="filter">FILTER</span>
</div>
Now, all you need is one click handler on #tabs span, and get the data-type of the span you clicked on. You can use that to filter on the classes of the other container elements.
The second thing is that you can attach handler to more than 1 element at the same time. So in your example, js('#sort-containers div').hide(); will hide all the div's that match the selector at once.
results
I changed some classes to ID's, and some classes to data attributes. Here's a fiddle: https://jsfiddle.net/mq9xk29y/
HTML:
<div id="tabs">
<span data-type="sort-by">SORT BY</span>
<span data-type="filter">FILTER</span>
</div>
<div id="sort-containers">
<div class="sort-by-container">Sort by click me here</div>
<div class="filter-container">Filter click me here</div>
</div>
JS:
js = $.noConflict();
var $tabs = js('#tabs span');
$tabs.click(function() {
var $clicked = js(this); //get the element thats clicked on
var type = $clicked.data('type'); //get the data-type value
$tabs.removeClass('active'); //remove active from all tabs
$clicked.addClass('active'); //add active to the current tab
js('#sort-containers div').hide(); //hide all containers
js('.' + type + '-container').show().addClass('active'); //add active to current container
});
As long as you follow the naming convention of data-type: bla in the tabs, and bla-container on the classes in sort-container, you never have to worry about coding for additional tabs.
There might still be things that could be further optimised, but at least it'll take care of the repetition.
Say I have a blank page and a button (somewhere in the top right corner). When I click that button I want to be able to create a square on the page (A contact card). And when I click it again I want to be able to create another card next to it with the same dimensions and so on (i.e every click adds a card till theres 4 in a roll then starts on the bottom of the card untill whole page is filled).
I am unsure on how I can accomplish this. I know how to insert a button and a click event just not sure how I can structure this. Would I need to use flex?
Thanks in advance,
I am trying to visualize how I can tackle this problem.
Would I need to use flex?
In 2016, flex would be the best way to approach creating horizontal rows, each containing 4 equal-width elements, yes.
But if you want a legacy-browser solution, you can also use
display: inline-block;
float: left;
width --px;
and a container with an explicitly specified width which means that every :nth-of-type(4n+1) element will start on a new row.
For instance:
.card {
display: inline-block;
float: left;
width: 100px;
margin: 12px;
}
means each card requires 124px of space (12px + 100px + 12px).
So if you give the .card-container an explicit width of 4 x 124:
.card-container {
width: 496px;
}
then after every 4 cards, the next card will begin on a new row.
Here's a quick prototype using jQuery and Twitter Bootstrap.
When pressing the button, the first card with class card-hidden is shown and has it's card-hidden class removed. The next button press will show the next card until there's no cards left.
HTML
<html>
<body>
<button id="button">Add</button>
<div class="container">
<div class="row">
<div class="card card-hidden col-xs-3">1</div>
<div class="card card-hidden col-xs-3">2</div>
<div class="card card-hidden col-xs-3">3</div>
<div class="card card-hidden col-xs-3">4</div>
</div>
</div>
</body>
</html>
CSS
.card {
height: 200px;
}
.card-hidden {
display: none;
}
JS
$("#button").on("click", function(e) {
if ($(".card-hidden").length > 0) {
$(".card-hidden").first().slideToggle(function() {
$(this).removeClass("card-hidden");
});
} else {
console.log("No more cards to show.");
}
});
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.
I'm playing around with building a basic modal window and i want it do dissapear when i click the edges. So my problem in it's most basic form:
<div style="width:100%;height:100%;" onclick="hideAll()">
Hide all onclick.
<div style="width:100px;height:100px;">
does not hide all onclick
</div>
</div>
What is the best way to achieve this? To use unnested divs? html/css magic?
HTML:
<div style="width:100%;height:100%;" class="outerModal">
Hide all onclick.
<div style="width:100px;height:100px;">
does not hide all onclick
</div>
</div>
JavaScript:
$(document).on("click", ".outerModal", function(evt) { //listen for clicks
var target = $(evt.target ||evt.srcElement); //get the element that was clicked on
if (target.is(".outerModal")) { //make sure it was not a child that was clicked.
//hide dialog
}
});
Example:
JSFiddle
When you hide the parent tag, it automatically hides the childen tag as well, You should first contain the child div into variable and after that hide the parent div and append that stored child div into parent tag something like this.
HTML
<div id="result">
<div style="width:100%;height:100%;" id="parentDiv" onclick="hideAll()">
Hide all onclick.
<div style="width:100px;height:100px;" id="childDiv">
does not hide all onclick
</div>
</div>
</div>
javaScript
function hideAll(){
var childDiv = document.getElementById('childDiv'); //contain child div
var parDiv = document.getElementById('parentDiv');
parDiv.style.display = 'none'; //hide parent div
parDiv.parentNode.appendChild(childDiv); //append child div
}
DEMO
Assuming that "parentDiv" is to be the background and "childDiv" is to be the actual modal content, the best way I have found is to separate the divs entirely.
HTML
<div id="parentDiv" onclick="hideAll()"> </div>
<div id="childDiv" >
does not hide all onclick
</div>
Javascript using jQuery
function hideAll(){
/* The Parent Div will hide everything when clicked, but the child won't */
$('#childDiv').fadeOut(1000, function(){
$('#parentDiv').fadeOut(1000);
});
}
CSS
#parentDiv {
background: black;
display: block;
position: fixed;
top: 0;
left: 0;
z-index: 100;
height: 100%;
width: 100%;
}
#childDiv {
display: block;
position: relative;
background: white;
height: 200px;
width: 200px;
z-index: 101
}
Here is a working example.
Hope this helps at all.
See this fiddle:
http://jsfiddle.net/eZp9D/
$(document).ready(function () {
$('#parentDiv').click(function (e) {
if ($(e.target).prop('id') == "parentDiv") {
$(this).hide();
}
});
});
You can use basic jQuery and style it accordingly with CSS.
Check this example.
If you want to have it disappear by clicking outside of the dialog window, make sure that onClick you perform this action:
$( "#dialog_id" ).dialog( "close" );