If statement to check css property not working - javascript

I have a div that displays a little popup menu when clicked. I want users to be able to click anywhere in the body of the site to close the popup, but when I add code for that, the popup cant be opened at all anymore.
So I tried adding an if-statement so that the closemenu() function will only try close the popup if its already open, but it seems like the statement is evaluating to false even if the popup is open.
Here is the HTML for showing the popup:
<div class="popcolor" onclick="showmenu()"> Click!
<span class="popupcolor" id="myPopup">Pop!</span>
</div>
Here is the css:
.popcolor .show {
visibility: visible;
-webkit-animation: fadeIn 0.5s;
animation: fadeIn 0.5s;
}
Here is the Javascript:
function showmenu() {
var popup = document.getElementById("myPopup");
popup.classList.toggle("show");
}
function closemenu() {
var popup = document.getElementById("myPopup");
if (popup.style.visibility == "visible") {
popup.classList.toggle("close");
};
}
Here is the HTML for closing the popup:
<body onclick="closemenu()">
I've been through every post I can find on this for solutions, and I'm still stuck. Any help is appreciated.

You can use the getComputedStyle() method on the window object, to calculate the style rules that result from the classes applied to your popup element.
This gives you a reliable way of determining the values of different styling rules that result from, say, the 'close' class being applied to popup
Something along the lines of this should work for you:
function closemenu() {
var popup = document.getElementById("myPopup");
// Get the computed style, that is the combination of styles
// resulting from your CSS classlist, etc
var computedStyle = window.getComputedStyle(popup, null);
// Get visibility value from computed styles
var visiblityValue = computedStyle.getPropertyValue("visibility")
if (visiblityValue == "visible") {
popup.classList.toggle("show"); // Correct this from "close" to "show"
};
}
There are also some other functional issues with your implementation which are causing problems. Consider updating your showmenu() method to:
function showmenu(event) {
// Prevent event propagation, which would cause closemenu to call
// after this method is called
event.stopPropagation()
var popup = document.getElementById("myPopup");
popup.classList.toggle("show");
}
For more information on getComputedStyle(), see the MDN documentation

Problem here is that click event triggered from div bubbles up to body which eventually closes the popup.
function showmenu(e) {
e.stopPropagation();
console.log('toggle');
document.getElementById("myPopup").classList.toggle("close");
}
function closemenu(e) {
e.stopPropagation();
console.log('hide');
document.getElementById("myPopup").classList.add("close");
}
#myPopup.close {
visibility: hidden;
}
body {
border: 1px solid #ccc;
padding: 2rem;
}
<body onclick="closemenu(event)">
<div class="popcolor" onclick="showmenu(event)"> Click!
<span class="popupcolor close" id="myPopup">Pop!</span>
</div>
</body>
P.S. Use event.stopPropagation() to cancel/consume event

Because the visibility property is being set at the class level, the style information isn't available in the style property of your element. Maybe instead of checking for a specific style, you can check to see if the 'show' class is currently assigned to your element like so:
function closemenu() {
var popup = document.getElementById("myPopup");
if (popup.classList.contains("show")) {
popup.classList.toggle("close");
};
}

Problem in your code is with the use of JavaScript functions.
Try this simple example I took from W3Schools and enhanced it for your case.
https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_add_class
There seems to be some issue with W3CSchool TryIt Editor page. Here is the link to JSBin for the same code: https://jsbin.com/xefolinape/edit?html,output
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.mystyle {
width: 100%;
padding: 25px;
background-color: coral;
color: white;
font-size: 25px;
box-sizing: border-box;
}
</style>
</head>
<body>
<p>Click the "Try it" button to add the "mystyle" class to the DIV element:</p>
<button onclick="myFunction()">Try it</button>
<button onclick="myFunctionClose()">Close it</button>
<script>
function myFunction() {
var element = document.getElementById("myDIV");
element.classList.add("mystyle");
}
function myFunctionClose() {
var element = document.getElementById("myDIV");
element.classList.remove("mystyle");
}
</script>
</body>
</html>
Hope this helps!

Related

Create repeated fade-out effect by using className Method and setInterval

Dears,
I have an assignment that is to create a repeated fade-out effect by using setInterval and using the DOM className method, below is my code:
<!DOCTYPE html>
<html>
<style>
.mystyle {
background-color: coral;
padding: 16px;
opacity: 0;
transition: opacity 1s linear;
}
</style>
<body>
<div id="myDIV"></div>
<p>Click the button to set a class for myDIV:</p>
<button onclick="setInterval()">Try it</button>
<script>
setInterval(change, 2000)
function change() {
function subchange1(){
document.getElementById("myDIV").className = "mystyle";
};
function subchange2(){
document.getElementById("myDIV").className = "";
};
}
</script>
</body>
</html>
However, it shows no change at all, could you tell me where i get wrong and how to correct it? Thanks very much!
You've used setInterval() as a user defined function. It needs two arguments one is callback function and other is time interval. You should've used and remove the setInterval in JS.
<button onclick="setInterval(change, 2000)">Try it</button>
In change() function you just declared the functions. You didn't call them back. It will not give you expected output even if you call them.
For your code to work you need to check if myDiv has class .mystyle. For that you'll need to use if-else statements.
Here's a Working code :-
let myDiv = document.getElementById("myDIV");
function change() {
if (myDiv.className === "mystyle") {
myDiv.className = "";
} else {
myDiv.className = "mystyle";
}
}
function startAnimation() {
setInterval(change, 2000);
};
#myDIV {
background-color: #1a8cff;
padding: 16px;
transition: opacity 1s linear;
}
.mystyle {
background-color: coral;
opacity: 0;
}
<div id="myDIV"></div>
<p>Click the button to set a class for myDIV:</p>
<button onclick="startAnimation()">Try it</button>
Since this is an assignment that you have to complete, I will only list the issue I notice and let you fix them as an exercise.
You have a <style> tag directly inside the <html>. You should have that style inside of a <head> element.
Code functions called inside of the <script> tag are executed directly and immediately. You are calling setInterval(change, 2000) directly so there is no need to to add it to the <button> tag. If you want the repeated action to only start when you press the button, you need to call setInterval, this line setInterval(change, 2000), inside of another function, like start for example. Then you add start to onclick like this: onclick="start()".
The change function has 2 function declarations in it but no function calls. This means that the two functions inside of it, subchange1 and subchange2 are never called. To use a function you need to call it. You should move those two functions outside, after the change function, and then you can call them by using subchange1() and subchange2().
That will fix your code issues but don't have correct logic to implement the function requirements. You can search for class toggle function and find different ways of doing it. I suggest in going with the one that better matches what you have already learned.
This looks like a medium to advanced assignment. The best way to solve these will be to start simple and test your code as you progess. It will be very dificult to write everything and test. I highly suggest you write a simple function call, like alert(7), and then add it to the button, test the button, then add it to a function, test the function with the button, then use it with setInterval. This will make sure you have things working before you add more complexity.
Good luck with you assignment :)
After few research, i found that it is highly the cause of the async nature of the codes of Javascript, i found using setTimeout can overcome this issue and my code is below:
<!DOCTYPE html>
<html>
<head>
<style>
.mystyle {
background-color: coral;
padding: 16px;
opacity: 0;
transition: opacity 1s linear;
}
</style>
</head>
<body>
<div id="myDIV" >
<p>I am myDIV.</p>
</div>
<p>Click the button to set a class for myDIV:</p>
<button onclick="change()">Try it</button>
<script>
function change(){
let abc = document.getElementById("myDIV");
abc.className = "mystyle";
setTimeout(function() {abc.className = "";}, 1000);
setTimeout(change, 2000);
};
</script>
</body>
</html>

Close popup when clicking on another popup eventListener

I've used eventListener to close popups when I click off them but the popup still shows when I click on another popup. Is there a way to fix this without changing too much of my code?
I'm new to JS so I'm keeping things as simple as possible. Ideally I want to keep the eventListener function because it works really well to close the popups without having to manually close each one, apart from this one thing.
var popup = document.getElementById("myPopup");
function myFunction() {
popup.classList.toggle("show");
}
window.addEventListener('click', ({ target }) => {
if (!target.closest('.popup') && popup.classList.contains('show')) myFunction();
});
var popup2 = document.getElementById("myPopup2");
function myFunction2() {
popup2.classList.toggle("show");
}
window.addEventListener('click', ({ target }) => {
if (!target.closest('.popup') && popup2.classList.contains('show')) myFunction2();
});
/* Popup container - can be anything you want */
.popup {
position: relative;
display: inline-block;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
/* The actual popup */
.popup .popuptext {
visibility: hidden;
width: 160px;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 8px 0;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -80px;
}
/* Popup arrow */
.popup .popuptext::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: #555 transparent transparent transparent;
}
/* Toggle this class - hide and show the popup */
.popup .show {
visibility: visible;
-webkit-animation: fadeIn 1s;
animation: fadeIn 1s;
}
<body style="text-align:center">
<h2>Popup</h2>
<div class="popup" onclick="myFunction()">Click me to toggle the popup!
<span class="popuptext" id="myPopup">A Simple Popup!</span>
</div>
<h2>Popup2</h2>
<div class="popup" onclick="myFunction2()">Click me to toggle the popup!
<span class="popuptext" id="myPopup2">A Simple Popup again!</span>
</div>
</body>
You're very close, but the way you've written it is making it difficult. We can better solve this using a forEach loop and generic function:
JSFiddle: https://jsfiddle.net/vpr4Lh62/
// constants
const SHOW_CLASS = 'show'
// clears any active popups by removing the show class from all popup texts
// note: could be further optimized by storing the "active" popup in a variable whenver it's clicked, and only unsetting that one in this function
const clearPopups = () => {
document.querySelectorAll('.popuptext').forEach(text => text.classList.remove(SHOW_CLASS))
}
// keep behavior to clear popups when clicking outside of popup
window.addEventListener('click', ({ target }) => {
if(!target.classList.contains('popup')) {
clearPopups()
}
})
// instead of creating click handlers for each popup, we can create them all at once using a forEach loop
// first grab all the popups on the page
const popups = document.querySelectorAll('.popup')
// set a click handler on each popup
popups.forEach(popup => {
// we can also set the event listener on the popup, instead on the entire window
popup.addEventListener('click', ({ target }) => {
// grab the first child, which will be the span
const span = popup.children[0]
// clear all the popups first
clearPopups()
// then set this one to be shown
span.classList.add(SHOW_CLASS)
})
})
This also means we can simplify our HTML:
<body style="text-align:center">
<h2>Popup</h2>
<!-- You should never use onclick, this is old. Click handlers should be set using javascript -->
<div class="popup">Click me to toggle the popup!
<!-- We also don't need the ID here anymore -->
<span class="popuptext">A Simple Popup!</span>
</div>
<h2>Popup2</h2>
<div class="popup">Click me to toggle the popup!
<span class="popuptext">A Simple Popup again!</span>
</div>
</body>
To keep it as simple and least amount of change (but by far not an ideal solution) is this:
For the window click handlers you need to be able to differentiate between the two popups, currently you are using a .popup class as a check if it's not the closest thing in both cases, so when you click on a second popup, the myFunction() is not executed.
What I added here is new class names to the popups, 'one' and 'two' respectively.
<body style="text-align:center">
<h2>Popup</h2>
<div class="popup one" onclick="myFunction()">Click me to toggle the popup!
<span class="popuptext" id="myPopup">A Simple Popup!</span>
</div>
<h2>Popup2</h2>
<div class="popup two" onclick="myFunction2()">Click me to toggle the popup!
<span class="popuptext" id="myPopup2">A Simple Popup again!</span>
</div>
</body>
Then in your javascript code you can target them by modifying the selectors ever so slightly:
var popup = document.getElementById("myPopup");
function myFunction() {
popup.classList.toggle("show");
}
window.addEventListener('click', ({ target }) => {
if (!target.closest('.popup.one') && popup.classList.contains('show')) myFunction();
});
var popup2 = document.getElementById("myPopup2");
function myFunction2() {
popup2.classList.toggle("show");
}
window.addEventListener('click', ({ target }) => {
if (!target.closest('.popup.two') && popup2.classList.contains('show')) myFunction2();
});
Again, this is by no means a good coding standard nor the best solution but effectively the simplest one with least alteration to the code.
I hope this helps in terms of making sense why the issue occurred in the first place.
This is the solution to your problem.
Mohd Belal Toggle popus JsFiddle
Points covered in this jsfiddle
1. 2 Popus have been taken for now
2. Popus will toggle other popup opened
3. Clicking on area other than popup will close the popup
Hope you got your solution #Joe

How can i make anchor unclickable after 10 seconds?

<html>
<head>
<style>
.inactiveLink {
pointer-events: none;
cursor: default;
}
</style>
</head>
<body>
<p> You have won a prize. Click here within <div id='clock'></div> seconds ...</p>
<script>
var time = 10;
var f = function counttime(){document.getElementById('clock').innerHTML--;}
function stoptime(){cleatInterval(f);}
if(time){
document.getElementById('clock').innerHTML = time;
var h = setInterval(f,1000);
setTimeout(function(){clearInterval(h);
document.getElementById('clock').innetHTML = "Time's up!";
}, time*1000);
}
</script>
</body>
</html>
I'm trying to create a basic webpage, that says "You have won a prize. Click here within 10 seconds ..." when it opens. You have 10 seconds to click "here" to get your prize. After 10 seconds, "here" should be unclickable. I added a CSS part about being unclickable, which is called "inactiveLink". I don't know how i should implement the change of anchor tag after 10 seconds, to JS. (I'm thinking about after 10 sec, a in HTML should be changed to a with id inactiveLink)
You were almost there :)
I would use a class that uses the CSS-rule pointer-events: none and then use JS to add that class to the link after 10 seconds:
const a = document.getElementById('a');
setTimeout(() => a.className = 'unclickable', 10000);
.unclickable { pointer-events: none; }
<a id="a" href="">Hurry up</a>
Use setAttribute to make it unclickable. Maybe make a class called "unclickable" with all of the CSS you want.
You can see this thread for more information on how to set your link so that it won't fire an event upon click. Check the second answer (not the one that the user marked as correct).
The best way to do it is by removing the attribute href removeAttribute("href");.
Note: that pointer-events:none only prevents mouse clicks but if you used the tab key and pressed ENTER over the link it will still be followed.
function myFunction() {
document.getElementById("anc").removeAttribute("href");
}
<a id="anc" href="google.com">Click Me.</a>
<button onclick="myFunction()">Disabler</button>
anchor tags dont have a disabled attribute, but one approach you can take is to style a button like a link. Something link this for example:
const buttonEl = document.querySelector('#target');
const handler = e => {
console.log('Button is still active!');
};
buttonEl.addEventListener('click', handler);
setTimeout(() => {
buttonEl.disabled = true;
}, 2000);
button {
all: unset;
color: blue;
cursor: pointer;
text-decoration: underline;
}
button:disabled {
color: gray;
cursor: not-allowed;
}
<button id="target" type="button">Click the button</button>

jQuery.one() event handler is not executing

I am Trying to use jQuery.one() to disable a button that shows an image of a tree after it is clicked. The showImage function works fine, but not .one.
Can I not use javascript inside of a jquery event handler?
html:
<div class="grove">
<button id="plant" onclick="showImage()">Plant Orange Tree</button>
</div>
<div id="orange-tree-template">
<div class="orange-tree">
<h2>Tree Name</h2>
<h3>etc...</h3>
css:
.display-tree-big{
background: url('../images/tree_big.jpg');
background-repeat: no-repeat;
height:1000px;
width:1000px;
border: solid black 2px;
}
#orange-tree-template { visibility: hidden; }
javascript
function showImage() {
var img = document.getElementById('orange-tree-template');
img.style.visibility = 'visible';
}
$(document).ready(function() {
$("#plant").one( "click", function() {
document.getElementById("#plant").disabled = true;
});
});
A couple of issues.
You have an inline onclick handler assigned to the button. This will not respect the jQuery.one method, so because of error 2 you could continue to click the button and showImage will be called.
The function assigned to the click event via jQuery.one() is being called, however the statement document.getElementById("#plant") should not contain #, thus the button was not disabled.
jQuery(function($) {
$("#plant").one("click", function() {
// yes of course you can use JavaScript
document.getElementById('orange-tree-template').style.visibility = 'visible';
this.disabled = true;
});
});
#orange-tree-template {
visibility: hidden;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<button id="plant">Plant Orange Tree</button>
<div id="orange-tree-template">
TEST
</div>
Also the jQuery.one() method does not disable anything, it just executes a callback at most once per element per event type.

Adapt code inside dokuwiki spoilers style?

To change selector so it only show/hides when i click the image i put spoiler/ popdown menu directly after .OS image. Right now the popdown is a child of the .OS container, so clicks on it are passed to the .OS click handler.
But the code isn't perfect because when i click the 1st MAC both spoilers are opened.
But I want that spoilers are opened one at a time
But the main problem is that I can't fix the javascript code properly inside these types of spoilers (dokuwiki class) inside <td> tags:
This is the javascript code I use :
<div class="dokuwiki">
<div class="right_page">
<div class="entry-content">
<script type="text/javascript" src="./zzzz_files/jquery.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$(".nonjs").removeAttr( "href"); //href is needed for users without JS
$('.OS').click(function(){
if($(".details").is(":visible"))
{
$(".details").not(":hidden").hide("slow");
return true;
}
else
{
$(".OS").not(this).each(function(i) {
$(".details").hide("slow");
});
$(".details").show("slow");
return false;
}
});
});
</script>
<style type="text/css">
<!--
.details {
display: none;
clear: both;
padding: 2px;
}
.nonjs{
cursor:pointer;
}
img {
border: 0px;
}
-->
</style>
I thought about doing a video to better explain the problem and provide the local version of files for testing code:
Thanks in advance
This code works:
$(document).ready(function(){
$(".nonjs").removeAttr( "href");
//href is needed for users without JS
$('.OS').click(function(e){
if(!$(e.target).parents('.details').length){
if($(this).find('.details').is(":visible"))
{
$(this).find('.details').not(":hidden").hide("slow");
return true;
}
else
{
$(this).find('.details').show("slow");
return false;
}
}
});
});
I don't know what you're asking but here is what I think you want:
When clicking on an image, show the details below it and hide all others. If the details are already visible, hide them. Clicking something inside the details should not affect anything.
Demo
$(document).ready(function(){
$(".nonjs").removeAttr( "href"); //href is needed for users without JS
$('.OS').click(function(){
var details = $(this).next(".details");
$(".details").hide("slow");
if(details.is(":hidden")) {
details.show("slow");
}
});
});

Categories