Setting a limit on number of checkboxes that can be chosen - javascript

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" />

Related

Connecting few "if" conditions

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>

how do i make my X button delete the specific object inside array?

first time that I'm posting here I'm very new to web development and programming in general.
I'm currently trying to make my X button to delete the specific object inside an array.
it goes like this- the user can make 3 yellow notes-the user the values and then it stored as an object and the function displayTasks() refreshes the the notes-inside displayTasks()-when the user press X it triggers the onclick() that needs to remove this certain object but instead it always removes the last note and object in the array
how do I make it choose the exact object that inside a div?
I hope I'm clear on this!
thanks is advance!
those are the notes
class Task{
constructor(mytask,mydate,mytime){
this.task=mytask;
this.date=mydate;
this.time=mytime;
}
}
const myTask = document.getElementById("task")
const date = document.getElementById("date")
const time = document.getElementById("time")
const save = document.getElementById("save")
const reset = document.getElementById("reset")
const paragraph = document.getElementById("mypara")
const taskRow = document.getElementById("taskRow")
const tasks = []
function addTask() {
// 1. add new note to tasks array
// 2. call displayNotes()
if (tasks.length > 2) {
return alert("Too Many Notes please Complete One");
}
tasks.push(new Task(myTask.value, date.value, time.value));
resetTask();
displayTasks();
}
function resetTask() {
myTask.value = '';
date.value = '';
time.value = '';
}
function deleteTask(index) {
tasks.splice(index, 1);
displayTasks();
}
function displayTasks() {
// 1. delete all inner html in tasks row
// 2. for each element in tasks array: add a task html to the tasks row
taskRow.innerHTML = "";
for (task in tasks) {
console.log(tasks)
let taskDiv = document.createElement("div");
taskDiv.setAttribute("class", "col-sm task");
let description = document.createElement("p");
description.setAttribute("class", "description");
description.innerHTML = `${tasks[task].task}<br>`
let finishDate = document.createElement("div");
finishDate.setAttribute("class", "date");
finishDate.innerHTML = `${tasks[task].date}`;
let escape = document.createElement("p");
escape.setAttribute("class", "escape glyphicon glyphicon-remove");
escape.innerHTML = `X`;
escape.onclick = function callback() {
deleteTask(task);
console.log(task);
// escape.onclick = function() {
// deleteTask(task);
// }
}
taskDiv.appendChild(escape)
taskDiv.appendChild(description);
taskDiv.appendChild(finishDate);
taskRow.appendChild(taskDiv);
}
}
body {
background-image: url("/jpglibrary/tile.gif");
position: absolute;
left: 450px;
}
.notes{
position: absolute;
}
/* .task_input{
overflow-y: auto;
} */
.notesInput{
position: relative;
padding: 10px;
margin: 10px;
background-image: url("jpglibrary/formbg.jpg");
}
.savebutton{
position: absolute;
left: 500px;
bottom: 30px;
}
.resetbutton{
position: absolute;
left: 500px;
bottom: 0px;
}
h1{
font-family: 'cuteFont';
text-align: center;
margin-top: 30px;
font-size: 8ch;
}
.innertext{
height: 188px;
width: 170px;
position: absolute;
top: 408px;
}
.date{
position: absolute;
padding: 4px;
bottom: 7px;
height: 28px;
width: 100px;
font-size: 13px;
}
.task{
background-image: url("/jpglibrary/notebg.png");
background-repeat: no-repeat;
height: 240px;
width: 100px;
padding: 0px;
animation: fadeIn ease 2s;
}
.description{
position:absolute;
top: 40px;
padding: 3px;
width: 175px;
height: 170px ;
overflow-y: auto;
}
.escape{
padding-left: 160px;
padding-top: 20px;
}
#font-face{
font-family: cuteFont;
src: url("fonts/CuteNotes.ttf");
}
#keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body id="main_body">
<div class='container'>
<h1>My Task Board</h1>
<!-- <div class="notes">
<img src="jpglibrary/formbg.jpg" class="mx-auto d-block">
<img src="jpglibrary/formbg.jpg" class="mx-auto d-block">
<img src="jpglibrary/formbg.jpg" class="mx-auto d-block">
</div> -->
<div class=notesInput>
<input type="text" placeholder="My task" id="task" class="task_input">
<br>
<div>
<label>Finish Date <br>
<input type="date" id="date">
</label>
</div>
<div>
<label>Finish Time<br>
<input type="time" id="time">
</div></label>
<div class="savebutton">
<input type="button" value="Save" onclick=addTask() id="save">
</div>
<div class="resetbutton">
<input type="button" onclick="resetTask()" value="Reset" id="reset">
</div>
</div>
<div id="tasksContainer" class="container">
<div id="taskRow" class="row">
</div>
</div>
</div>
</body>
<script src="Task.js"></script>
<script src="script.js"></script>
</html>
You just need to get the index of the clicked task an give that index to deleteTask().
escape.addEventListener('click', function callback(e) {
var child = e.target.parentElement;
var container = child.parentElement;
var index = Array.prototype.slice.call(container.children).indexOf(child)
deleteTask(index);
});
Working example:
class Task{
constructor(mytask,mydate,mytime){
this.task=mytask;
this.date=mydate;
this.time=mytime;
}
}
const myTask = document.getElementById("task")
const date = document.getElementById("date")
const time = document.getElementById("time")
const taskRow = document.getElementById("taskRow")
const tasks = []
function addTask() {
if (tasks.length > 2) {
return alert("Too Many Notes please Complete One");
}
tasks.push(new Task(myTask.value, date.value, time.value));
resetTask();
displayTasks();
}
function resetTask() {
myTask.value = "";
date.value = "";
time.value = "";
}
function deleteTask(index) {
tasks.splice(index, 1);
displayTasks();
}
function displayTasks() {
taskRow.innerHTML = '';
for (task in tasks) {
let taskDiv = document.createElement("div");
taskDiv.setAttribute("class", "col-sm task");
let description = document.createElement("p");
description.setAttribute("class", "description");
description.innerText = `${tasks[task].task}`;
let finishDate = document.createElement("div");
finishDate.setAttribute("class", "date");
finishDate.innerText = `${tasks[task].date}`;
let escape = document.createElement("p");
escape.setAttribute("class", "escape glyphicon glyphicon-remove");
escape.innerText = 'X';
escape.addEventListener('click', function callback(e) {
var child = e.target.parentElement;
var container = child.parentElement;
var index = Array.prototype.slice.call(container.children).indexOf(child)
deleteTask(index);
});
taskDiv.appendChild(escape)
taskDiv.appendChild(description);
taskDiv.appendChild(finishDate);
taskRow.appendChild(taskDiv);
}
}
.container {
width: 250px;
text-align: center;
}
.inputs, #taskRow {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.task {
border: 1px solid black;
text-align: left;
}
.escape {
cursor: pointer;
text-align: right;
margin: 0;
}
<div class='container'>
<h1>My Task Board</h1>
<div class=notesInput>
<div class="inputs">
<label for="task">Task</label>
<input type="text" placeholder="My task" id="task" class="task_input">
</div>
<div class="inputs">
<label for="date">Finish Date</label>
<input type="date" id="date">
</div>
<div class="inputs">
<label for="date">Finish Time</label>
<input type="time" id="time">
</div>
<div class="inputs">
<input type="button" onclick="resetTask()" value="Reset" id="reset">
<input type="button" value="Save" onclick=addTask() id="save">
</div>
</div>
<div id="tasksContainer" class="container">
<div id="taskRow" class="row"></div>
</div>
</div>

Hide div when clicked outside without using addEventListener

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>

JavaScript - Shift Focus to Hovered Element

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>

How to change input pseudo class with Javascript?

I'm trying to build a 'radio button' selection style list, but not actually using input type="radio". My backend developer has advised me I need to create this using type="checkbox" in our specific case. I believe this can be done with JS.
So how can I make it so that when 1 option is in checked state, the other is unchecked using JS? Here is what I have so far:
http://codepen.io/rjtkoh/pen/VLZrMo
<label for="toggle-1">
<input type="checkbox" id="toggle-1">
<div>option A</div>
</label>
<label for="toggle-2">
<input type="checkbox" id="toggle-2">
<div>option B</div>
</label>
and CSS:
/* Checkbox Hack */
input[type=checkbox] {
position: absolute;
top: -9999px;
left: -9999px;
}
/* Default State */
div {
background: green;
width: 400px;
height: 100px;
line-height: 100px;
color: white;
text-align: center;
margin-bottom: 20px;
}
/* Toggled State */
input[type=checkbox]:checked ~ div {
background: red;
}
I've had a look at other threads talking about changing pseudo classes via JS, but my case dealing with input types confuses me.
Why do you need to do this with a checkbox if the sematics work for radio? There may be a legitimate reason, but without knowing this, I'd suggest you use a radio group instead, which will work without any JavaScript whatsoever, you just need to set a common name attribute on both inputs:
input[type=radio] {
position: absolute;
top: -9999px;
left: -9999px;
}
/* Default State */
div {
background: green;
width: 400px;
height: 100px;
line-height: 100px;
color: white;
text-align: center;
margin-bottom: 20px;
}
/* Toggled State */
input[type=radio]:checked + div {
background: red;
}
<label for="toggle-1">
<input type="radio" name="option" id="toggle-1">
<div>option A</div>
</label>
<label for="toggle-2">
<input type="radio" name="option" id="toggle-2">
<div>option B</div>
</label>
Here is a pure javascript solution since I don't see jQuery tags in your question:
If you REALLY need to do this with checkboxes you can do this:
html
<div id="radio_group">
<label for="toggle-1">
<input type="checkbox" id="toggle-1">
<div>option A</div>
</label>
<label for="toggle-2">
<input type="checkbox" id="toggle-2">
<div>option B</div>
</label>
</div>
javascript
var options = document.getElementById('radio_group').childNodes;
var checkboxes = document.getElementsByTagName('input');
function uncheck() {
for (var i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].type == 'checkbox') {
checkboxes[i].checked = '';
}
}
}
function checkBox(e) {
e.preventDefault();
if(e.target.nodeName == 'DIV') {
uncheck();
e.target.previousElementSibling.checked = 'checked';
}
}
for (var i = 0; i < options.length; i++) {
options[i].addEventListener('click', checkBox, false);
}
heres a fiddle --> https://jsfiddle.net/tL68Lsub/
If you really need the checkbox to work as a radio, you can use:
$("input[type='checkbox']").click(function () {
if ($(this).is(":checked")) {
$("input[type='checkbox']").not(this).removeAttr("checked");
$(this).attr("checked", "true");
}
})

Categories