I have a set of buttons that trigger different functions on the page. The user can hover on the desired button and click on it, as normal, or can navigate through the buttons with the up and down arrow keys and press the enter key to trigger the corresponding function.
Using the arrow keys, the button that is currently focused has a different color from the others (green). Buttons that are hovered are also green.
As things are right now, it is possible for more than one button to be green: The hovered one and the focused one. I don't want this to happen.
The ideal solution would be to change the focus to whichever button is hovered. Is this possible? If so, how can I achieve this? Preferebly without resorting to jQuery.
This is what I am working with:
var inputs = document.getElementsByClassName("move");
for (var i = 0; i < inputs.length; i++)
inputs[i].addEventListener("keyup", function(event) {
if (event.keyCode == 38) {
if (this.previousElementSibling) {
this.previousElementSibling.focus();
}
} else if (event.keyCode == 40) {
if (this.nextElementSibling) {
this.nextElementSibling.focus();
}
}
}, false);
.move {
display: block;
width: 200px;
padding: 10px;
text-align: center;
background-color: aquamarine;
margin-top: 10px;
}
.move:hover, .move:focus {
background-color: greenyellow;
}
<input class="move" type="button" value="1" autofocus />
<input class="move" type="button" value="2" />
<input class="move" type="button" value="3" />
You can use the mouseover event with focus function for that. Should work fine...
var inputs = document.getElementsByClassName("move");
for (var i = 0; i < inputs.length; i++) {
inputs[i].addEventListener("keyup", function(event) {
if (event.keyCode == 38) {
if (this.previousElementSibling) {
this.previousElementSibling.focus();
}
} else if (event.keyCode == 40) {
if (this.nextElementSibling) {
this.nextElementSibling.focus();
}
}
}, false);
inputs[i].addEventListener("mouseover", function(event) {
this.focus();
}, false);
}
.move {
display: block;
width: 200px;
padding: 10px;
text-align: center;
background-color: aquamarine;
margin-top: 10px;
}
.move:hover, .move:focus {
background-color: greenyellow;
}
<input class="move" type="button" value="1" autofocus />
<input class="move" type="button" value="2" />
<input class="move" type="button" value="3" />
I'm not a big fan of using mouseover to shift focus. If you don't want the hover state to display if a field has focus you can add a wrapping div and use focus-within.
As focus-within is not supported in ie and edge you can add mimic this using a .enable-hover class you toggle on focus/blur
const wrapper = document.querySelector('.group');
[].slice
.call(document.querySelectorAll('.move'))
.map(input => {
input.addEventListener('focus', e => {
wrapper.classList.remove('enable-hover')
});
input.addEventListener('blur', e => {
wrapper.classList.add('enable-hover')
});
input.addEventListener('keyup', e => {
if (e.keyCode == 38 && input.previousElementSibling)
input.previousElementSibling.focus();
if (e.keyCode == 40 && input.nextElementSibling)
input.nextElementSibling.focus();
});
})
.group:not(:focus-within) > .move:hover,
.group.enable-hover > .move:hover,
.move:focus {
background: greenyellow;
}
.move {
display: block;
width: 200px;
padding: 10px;
text-align: center;
background-color: aquamarine;
margin-top: 10px;
}
<div class="group">
<input class="move" type="button" value="1" autofocus />
<input class="move" type="button" value="2" />
<input class="move" type="button" value="3" />
</div>
Related
I have 12 <a> tags and they are linked to image. What i want to do is to connect all of them in one if as a .clicked == true. For some reason it does not work so here i am with another question.
A sample of my <a> tag.
<div id="container">
<div id="slider">
</div>
<div id="wypelniacz">
<img style="top: 22%; right: 60%;" alt="" src="greenapple.png" class="apl" id="apple1" onclick="imageSwap(1) ; this.onclick=null;">
</div>
</div>
JS
function imageSwap(id)
{
document.getElementById("apple" + id).src = "redapple.png";
}
To make it easier to explain i have posted a picture of what am i doing.
When apple is not clicked it remains green, but when i click on it, it will change to red.
Then, when all 12apples are red the whole div copntent will be deleted and swapped for one image. How can i possibly do that? Thanks in advance!
So add a class for attribute and check how many you have
function imageSwap(id) {
var img = document.getElementById("apple" + id);
img.src = "redapple.png";
img.classList.add("selected");
var count = document.querSelectorAll(".selected").length;
console.log(count);
}
or just with html and css
document.querySelector(".tree").addEventListener("change", function(evt) {
const checked = document.querySelectorAll(".apple:checked").length;
console.log(checked);
console.log(evt.target.form.checkValidity());
});
.apple {
display: none;
}
.apple + label {
display: inline-block;
width: 100px;
height: 100px;
background-image: url(http://placekitten.com/g/100/100);
}
.apple:checked + label {
background-image: url(http://placekitten.com/100/100);
}
<form class="tree">
<input type="checkbox" class="apple" id="apple1" required><label for="apple1"></label>
<input type="checkbox" class="apple" id="apple2" required><label for="apple2"></label>
<input type="checkbox" class="apple" id="apple3" required><label for="apple3"></label>
<input type="checkbox" class="apple" id="apple4" required><label for="apple4"></label>
<input type="checkbox" class="apple" id="apple5" required><label for="apple5"></label>
<button>Next</button>
</form>
Use event delegation, that is I attach a click event to '.container', and use 'event.target' to manipulate the target apple
toggle target apple class to switch background-color
check all apples, if there is no '.red', then switch to a new image(Here I just remove the '.red' class all)
document.addEventListener('DOMContentLoaded', ev => {
const apples = [...document.querySelectorAll('.apple')]
const container = document.querySelector('.container')
container.addEventListener('click', ev => {
if (ev.target.matches('.apple')) {
ev.preventDefault()
ev.target.classList.toggle('red')
const apples = [...container.querySelectorAll('.apple')]
if (apples.every(apple => apple.classList.contains('red'))) {
apples.forEach(apple => apple.classList.remove('red'))
}
}
})
}, false)
div {
display: flex;
flex-flow: row wrap;
justify-content: space-evenly;
align-items: center;
}
.apple {
width: 5rem;
height: 5rem;
border-radius: 5rem;
background: green;
}
.green {
background: green;
}
.red {
background: red;
}
<div class="container">
</div>
I'm trying to do a function that when I press the enter key it disappears a div (containerMessage) and another (containerResult) one appears, what am I doing wrong? When I press the enter key the function is not even called
A Live Example
HTML
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="bloco">
<h1>NSGM</h1>
<h2>Namorada Super Gostosa e Modelo</h2>
<img src="girlfriend.png">
<div id="containerMessage">
<p id="message">Qual seu nome meu amor</p>
<form>
<input type="text" name="name" id="digitarNome">
</form>
<div id="containerResult">
<p id="result">EU TE AMO RODRIGO</p>
</div>
</div>
</div>
<script src="NSGM.js"></script>
</body>
</html>
Javascript
var digitarNome = document.getElementById("digitarNome");
digitarNome.addEventListener("keydown", function (e) {
if (e.keyCode === 13) {
validate(e);
}
});
function validate(e) {
if (document.getElementById('containerMessage').style.display == 'block') {
document.getElementById('containerMessage').style.display = 'none'
document.getElementById('containerResult').style.display = 'block'
}
}
When you press enter, the form gets submitted, so you'll have to prevent that default behaviour:
var digitarNome = document.getElementById("digitarNome");
digitarNome.addEventListener("keydown", function (e) {
if (e.keyCode === 13) {
e.preventDefault(); // Prevent submitting the form
validate(e);
}
});
The other issue is that you're hiding the containerMessage div which contains your containerResult, so it will never be shown. Check the snippet below, but basically you'll just have to move the containerResult div out of the containerMessage div.
var digitarNome = document.getElementById("digitarNome");
digitarNome.addEventListener("keydown", function(e) {
if (e.keyCode === 13) {
e.preventDefault();
validate(e);
}
});
function validate(e) {
let container = document.getElementById("containerMessage");
if (!container.style.display || container.style.display == "block") {
container.style.display = "none";
document.getElementById("containerResult").style.display = "block";
}
}
body {
background-color: red;
margin: 0;
}
img {
height: 50vh;
}
#bloco {
text-align: center;
margin: 0;
position: absolute;
top: 45%;
left: 50%;
transform: translate(-50%, -50%);
white-space: nowrap;
}
h1 {
margin: 100px 0px 0px 0px;
font-size: 10em;
}
h2 {
margin: 0;
font-size: 3em;
}
p {
font-size: 3em;
margin: 0;
}
h1,
h2,
p {
color: white;
}
input[type="text"] {
margin: 50px 0px 0px 0px;
padding: 16px 20px;
border: none;
border-radius: 8px;
background-color: #f1f1f1;
font-size: 2em;
text-align: center;
}
input[type="text"]:focus {
background-color: #ea8079;
color: white;
outline: 0;
}
#result {
font-size: 6em;
}
#containerResult {
display: none;
}
#containerMessage {
display: block;
}
<div id="bloco">
<h1>NSGM</h1>
<h2>Namorada Super Gostosa e Modelo</h2>
<div id="containerMessage">
<p id="message">Qual seu nome meu amor</p>
<form>
<input type="text" name="name" id="digitarNome" />
</form>
</div>
<div id="containerResult">
<p id="result">EU TE AMO RODRIGO</p>
</div>
</div>
The problem is that .style.display will only return the current style if it has been previously set inline or via javascript.
Otherwise, you must use:
getComputedStyle(element, null).display
where element is previously selected in the DOM.
I removed the form from the example to remove that distraction.
var digitarNome = document.getElementById("digitarNome");
digitarNome.addEventListener("keydown", function(e) {
if (e.keyCode === 13) {
validate(e);
}
});
function validate(e) {
let msgDiv = document.getElementById('containerMessage');
let resDiv = document.getElementById('containerResult');
let divStyle = getComputedStyle(msgDiv, null).display;
if (divStyle == 'block') {
msgDiv.style.display = 'none';
resDiv.style.display = 'block';
}
}
#containerResult{display:none;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div id="bloco">
<div id="containerMessage">
Nome meu amor: <input type="text" name="name" id="digitarNome">
</div>
<div id="containerResult">
<p id="result">EU TE AMO RODRIGO</p>
</div>
</div>
References:
https://stackoverflow.com/a/4866269/1447509
Element.style will only retrieve the styles from the attribute on the element so
document.getElementById('containerMessage').style.display == 'block'
Will always return false
From W3 schools https://www.w3schools.com/jsref/prop_html_style.asp
Note: The style property only returns the CSS declarations set in the element's inline style attribute, e.g.
. It is not possible to use this property to get information about style rules from the section in the document or external style sheets.
You can instead apply the display style as in line attribute like so
<div id="containerMassage" style="display:block"></div>
How can I hide a <div> when I click outside it using onblur? I tried with the code below, but when I click the checkbox it disappears, and when I click outside of it, it won’t disappear.
I then tried using window or document object which works, but is not supported by the platform that I’m currently using.
Is this otherwise possible using JavaScript and/or CSS?
var expanded = false;
function showshow() {
var show = document.getElementById("show");
if (!expanded) {
show.style.display = "block";
expanded = true;
} else {
show.style.display = "none";
expanded = false;
}
}
function hideshow() {
var show = document.getElementById("show");
if (expanded) {
show.style.display = "none";
expanded = false;
}
}
#show {
position: absolute;
width: 200px;
display: none;
border: 1px solid #000000;
background-color: #ffffff;
}
#show label {
display: block;
white-space: nowrap;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
#show label:hover {
background-color: #eff1f4;
}
<form id="input-form">
<button type="button" onclick="showshow()">Select an option</button>
<div id="show" tabindex="1" onblur="hideshow()">
<label for="OptionA">
<input type="checkbox" id="OptionA" value="Option A" />Option A</label>
<label for="OptionB">
<input type="checkbox" id="OptionB" value="Option B" />Option B</label>
<label for="OptionC">
<input type="checkbox" id="OptionC" value="Option C" />Option ABCDEFGHIJKLMNOPQRSTUVWXYZ</label>
</div>
</form>
if you can't use addEventListener on your platform maybe you can try attachEvent that will do the job on old platform.
Exemple:
if (document.addEventListener) { // For all major browsers, except IE 8 and earlier
document.addEventListener("click", myFunction);
} else if (document.attachEvent) { // For IE 8 and earlier versions
document.attachEvent("onclick", myFunction);
}
Best regards :)
You will have to call the hideshow function when the click event is fired on the document's body, then check if the event's target is document.body:
var expanded = false;
function showshow(event) {
var show = document.getElementById("show");
if (!expanded) {
show.style.display = "block";
expanded = true;
} else {
show.style.display = "none";
expanded = false;
}
}
function hideshow(event) {
var show = document.getElementById("show");
var elem = event.target;
// Check if the event's target is the document's body
if(elem && elem.id == "main") {
show.style.display = "none";
expanded = false;
}
}
document.body.onclick = hideshow;
html,
body,
#main {
height: 100%;
width: 100%;
}
#show {
position: absolute;
width: 200px;
display: none;
border: 1px solid #000000;
background-color:#ffffff;
}
#show label {
display: block;
white-space: nowrap;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
#show label:hover {
background-color: #eff1f4;
}
<main id="main">
<button type="button" id="toggle-modal" onclick="showshow(event)">Select an option</button>
<div id="show" tabindex="1" onblur="hideshow(event)">
<label for="OptionA">
<input type="checkbox" id="OptionA" value="Option A" />
Option A
</label>
<label for="OptionB">
<input type="checkbox" id="OptionB" value="Option B" />Option B
</label>
<label for="OptionC">
<input type="checkbox" id="OptionC" value="Option C" />Option ABCDEFGHIJKLMNOPQRSTUVWXYZ
</label>
</div>
</main>
I have a form which is initially hidden.
There is two steps of click flow to reach the form. I need to reset the initial click action when the form close button is clicked.
Adding the sample code and demo.
Here goes the flow
Click on the Join Now text
Then click on the text Click here to open the form text
Then click on the close icon
There comes the pop up
What I now need to know is,
By clicking on Yes , the form needs to be reset and the screen should look like how it looked initially (Brand name box with join now text) and the initial click action of join now should be refreshed.
By clicking on No, it should remain on the same form.
$(".button").click(function(e){
e.preventDefault();
$(this).hide();
$(".slidethis").fadeIn(800).css("display","inline-block");
$(".wrapper").css("display","block");
});
$(".seconddiv").hide();
//forstdiv click
$(".firstdiv").click(function(){
$(this).hide();
$(".seconddiv").show();
});
//Close button
$(".close_icon").click(function(){
$(".popup").show();
});
Demo Here
P.S: I don't want to refresh the page by closing the form.
Adding this code should do it. It's about reversing your steps:
$("input[value=Yes]").click(function(){
//reset - reverse all the steps
$(".button").show();
$(".slidethis").fadeOut(800).css("display","none");
$(".wrapper").css("display","inline-block");
$(".popup").hide();
$(".seconddiv").hide();
$(".firstdiv").show();
});
$("input[value=No]").click(function(){
$(".popup").hide();
});
Updated fiddle: https://jsfiddle.net/5353ntuf/5/
Working fiddle.
You should add an event click on the both buttons Yes and No, so give them a common class , e.g confirm class:
<input type="button" class='confirm' value="Yes" />
<input type="button" class='confirm' value="No" />
Then add a condition to check which action you're going to perform, like :
//Confirm buttons
$("body").on("click", ".confirm", function() {
$(".popup").hide();
if ($(this).val() == 'No')
{
$('form input').val(""); //Reset form
} else {
$(".seconddiv,.slidethis").hide();
$(".firstdiv,.button").show();
$(".wrapper").css("display", "inline-block");
}
});
Hope this helps.
//slide open the main panel
$(".button").click(function(e) {
e.preventDefault();
$(this).hide();
$(".slidethis").fadeIn(800).css("display", "inline-block");
$(".wrapper").css("display", "block");
});
$(".seconddiv").hide();
//forstdiv click
$(".firstdiv").click(function() {
$(this).hide();
$(".seconddiv").show();
});
//Close button
$(".close_icon").click(function() {
$(".popup").show();
});
//Confirm buttons
$("body").on("click", ".confirm", function() {
$(".popup").hide();
if ($(this).val() == 'No') {
$('form input').val("");
} else {
$(".seconddiv,.slidethis").hide();
$(".firstdiv,.button").show();
$(".wrapper").css("display", "inline-block");
}
});
.wrapper {
background: #9ac366;
display: inline-block;
}
.headcard {
display: inline-block;
text-align: center;
padding: 3% 30px;
float: left;
}
.slidethis {
background: #b67fd8;
padding: 20px 0;
width: 70%;
vertical-align: top;
position: relative;
height: 228px;
display: none;
position: relative
}
.firstdiv,
.seconddiv {
width: 200px;
border: #888 solid 2px;
padding: 20px;
}
.close_icon {
background: #333;
color: #fff;
padding: 4px;
float: right;
margin-top: -20px;
text-decoration: none
}
.popup {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
background: #e4e4e4;
text-align: center;
padding-top: 5%;
display: none
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="headcard">
<h4>Brand Name</h4>
Join Now
</div>
<!--this is hidden by default-->
<div class="slidethis">
<div class="firstdiv">
Click here to open the form
</div>
<div class="seconddiv">
<form>
X
<input placeholder="name" />
<input placeholder="email" />
</form>
<!--close pop up-->
<div class="popup">
Closing will clear the form data. Do you want ot close?
<br/>
<input type="button" class='confirm' value="Yes" />
<input type="button" class='confirm' value="No" />
</div>
</div>
</div>
</div>
I have searched other similar questions on here and tried to replicate them, but I am unsure what I am doing wrong.
I am only wanting one checkbox to be able to be checked. I set the limit with limitCal and am checking the siblings.
Anyone see what I am doing wrong?
jQuery.fn.fadeBoolToggle = function (bool) {
return bool ? this.fadeIn(400) : this.fadeOut(400);
}
function packageSelect() {
var limitCal = 1;
$('.calendar-check').on('change', function () {
$(this).parents('.product-wrap:first').find('.checkmark-img').fadeBoolToggle(this.checked);
if ($(this).siblings(':checked').length >= limitCal) {
this.checked = false;
}
$('#next1').fadeBoolToggle($('.product-check:checked').length > 0);
var prods = [];
$('.calendar-check:checked').each(function () { prods.push($(this).val()) });
});
};
packageSelect();
.calendar-check {
display: none;
}
.product-wrap {
width: 100%;
position: relative;
display: block;
}
.checkmark-img {
display: none;
width: 40%;
height: auto;
z-index: 1;
cursor: pointer;
}
.package-check-toggle {
position: relative;
height: 100%;
width: 100%;
display: block;
}
.package-setup {
display: none;
margin: 40px 0;
width: 100%;
}
#calendar-box-wrap {
margin: 20px 0;
}
.calendar-box {
display: inline-block;
vertical-align: top;
width: 25%;
margin: 0 4%;
position: relative;
}
.calendar-selection-img {
width: 100%;
height: auto;
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="calendar-box">
<div class="product-wrap">
<label for="cal-2year" class="package-check-toggle">
<img src="images/calendar-package.png" alt="2-year Photo Gift" class="calendar-selection-img">
<img src="images/checkmark-circle.png" class="checkmark-img total-center">
</label>
<input type="checkbox" class="calendar-check" id="cal-2year" value="2-year Calendar">
</div>
</div><div class="calendar-box">
<div class="product-wrap">
<label for="cal-whiteboard" class="package-check-toggle">
<img src="images/calendar-package.png" alt="Whiteboard Photo Gift" class="calendar-selection-img">
<img src="images/checkmark-circle.png" class="checkmark-img total-center">
</label>
<input type="checkbox" class="calendar-check" id="cal-whiteboard" value="Whiteboard Calendar">
</div>
</div>
Here's a simplified version of what you're trying to do. Basically, intercepting the click event of the checkbox allows you to prevent the default action (checking the checkbox). The value of checked for this is going to be the value it would be if the click is successful. So, if the checkbox would be unchecked, let the click happen. Also let the click happen if the number of checked checkboxes is less than or equal to the limit. Otherwise, stop the checkbox from getting checked. I've set the limit for this example to 2 just for demonstration.
var limit = 2;
$('input:checkbox').on('click', function (e) {
if (!this.checked || $('input:checkbox:checked').length <= limit) {
return true;
}
return false;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="checkbox">
<input type="checkbox">
<input type="checkbox">
<input type="checkbox">
const allCheckBoxs = document.querySelectorAll("input")
let limit = 2
allCheckBoxs.forEach( el => {
el.addEventListener("click", e => {
if(el.checked){
limit--
if(limit < 0){
e.preventDefault();
console.log("Sorry, you are over the limit")
}
}else{
limit++
console.log(limit)
}
})
})
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />
<input type="checkbox" />