I am working on a form and in that I am using radio buttons but because of the styling issues i just hides them by display: none property. And done all the styling on its corresponding label element.
<form>
<div class="radio-input">
<input type="radio" style="display:none;" name="color" value="green" id="g2" />
<label class="square-box" for="g2"></label>
<input type="radio" style="display:none;" name="color" value="blue" id="b2" />
<label class="square-box not-allowed" for="b2"></label>
</div>
</form>
Now I have attached and event listener on that parent div and waiting for an event to bubble. But when i click label, event.target returns both label and input element. So that creates a problem.
document
.querySelector(".radio-input")
.addEventListener("click", function (event) {
if (event.target.classList.contains("not-allowed")) {
// do something...
} else {
// do something...
}
};
So in this if label has not-allowed class i wanna do some operation but because event.target returns both the elements, addeventlistener runs twice and fails the code(basically if condition).
So the two possible solutions might be
just ignore input elements by adding a condition in the if
event.target somehow don't return the input element
whatever the solution be please tell me!
As this answer, you can stop default behaviour of the addEventListener like this:
document
.querySelector(".radio-input")
.addEventListener("click", function (event) {
event.preventDefault(); // adding this to your code
if (event.target.classList.contains("not-allowed")) {
console.log("not allowed");
} else {
console.log("allowed");
}
});
You can also ignore input element:
document
.querySelector(".radio-input")
.addEventListener("click", function (event) {
if(event.target.nodeName === 'INPUT')return; // if it's input, just return
if (event.target.classList.contains("not-allowed")) {
// do something...
} else {
// do something...
}
};
As mentioned above preventDefault() or possibly stopimmediatepropagation()
Related
When setup like this, clicking on a label that has a child button triggers button's onclick event:
function fireButton() {
console.log("Button fired!");
}
<label>Label
<button onclick="fireButton()">Button</button>
</label>
is there a way to prevent this?
Add for attribute to label.
function fireButton() {
console.log("Button fired!");
}
<label for=''>Label
<button onclick="fireButton()">Button</button>
</label>
You can put the button outside the label
<label>Label</label>
<button onclick="fireButton()">Button</button>
You can add preventDefault for labels and keep the existing code:
document.querySelector("label").addEventListener("click", function(event) {
event.preventDefault();
}, false);
You could use a different tag e.g <span> rather than the label But if you really need to use the <label>, you should prevent the default behaviour of the label onclick() like so:
function fireButton(){
//add actions here
}
function preventDefault(event){
event.preventDefault()
}
<label onclick="preventDefault(event)">Label
<button onclick="fireButton()">Button</button>
</label>
Here's an approach in CSS which also disables triggering button's :active state when clicking on label. Overriding label's onClick event does not do that.
label {
pointer-events: none;
}
button {
pointer-events: initial;
}
I have a situation where I have a click event attached to an element's onClick attribute and also a click event that fires on any element with a specific class. The element's onClick event causes a panel on the page to close. The class's onClick event causes the page to scroll to an element lower on the page.
The problem is that both seem to fire at the same time causing the page to scroll beyond the targeted element. Here is a code sample:
$(document).ready(function() {
$('.proceed').on("click", function() {
$('html, body').animate({
scrollTop: $(this).closest('.item-section').next().offset().top
}, 2000);
})
});
function openPanel() {
var rb1 = $("#radioButton1").is(':checked');
alert("Clicked");
$('#containerBox1').toggle(rb1);
}
.item-section {
height: 500px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="">
<div class="item-section">
<p>Choose a food</p>
<input type="radio" id="radioButton1" name="food" value="pizza" onclick="openPanel()">Pizza<br>
<div id="containerBox1" style="display: none;">
<p>Choose a topping</p>
<input type="radio" name="topping" value="pepperoni">Pepperoni<br>
<input type="radio" name="topping" value="vegetarian">Vegetarian<br>
<button class="proceed">Proceed to next section</button>
</div>
<input type="radio" name="food" value="burger" class="proceed">Burger<br>
<input type="radio" name="food" value="fish" class="proceed">Fish
</div>
<div class="item-section">
<p>Drink selection would be here</p>
</div>
</form>
Does anyone know how to fix this keeping in mind that my real code is much larger than the sample provided and has more classes and buttons.
You could try
extract the .proceed click handler to a named function
call that named function from the .proceed click handler
in openPanel, do whatever the function needs to do, then call the scroll handler, then call stopPropagation on the event
In other words, don't allow two click handlers to fire for your radio button, but have one click handler that does both tasks and then stops propagation.
You don't need two onclick events. Just process the one for .proceed and check to see if rb1 is checked.
$(document).ready(function() {
$('.proceed').on("click", function() {
var rb1 = $("#radioButton1").is(':checked');
if( rb1 ) {
alert("Clicked");
$('#containerBox1').toggle(rb1);
}
$('html, body').animate({
scrollTop: $(this).closest('.item-section').next().offset().top
}, 2000);
})
});
I am trying to finalise design of a product page and basket template for my new site but am having trouble putting all the pieces together.
In the html code below the cart/basket is called using <div class="ct-cart"></div> but I need this to either not be visible or blanked out in some way so that a customer has to have ticked the checkbox to agree with the terms and conditions before they can interact with the cart/basket.
I've tried a few scripts I've found online to try and hide it but have been unable to get it to work, even after (hopefully) removing any jQuery conflicts.
Any help would be greatly appreciated.
<p style="text-align:center">
<input type="checkbox" name="tandc" id="tandc" value="true" class="form-control"><label for="tandc"> Please tick box above to confirm you agree with the Terms & Conditions.</label>
</p>
<div class="ct-cart"></div>
Pure JS implementation. (in case you dont really need jquery)
document.getElementById('tandc').onchange = function(){
var cart = document.getElementsByClassName('ct-cart')[0];
if (this.checked) cart.classList.remove('hide');
else cart.classList.add('hide');
}
.hide{
display: none;
}
<p style="text-align:center">
<input type="checkbox" name="tandc" id="tandc" value="true" class="form-control"><label for="tandc"> Please tick box above to confirm you agree with the Terms & Conditions.</label>
</p>
<div class="ct-cart hide">Shown only if checked :)</div>
Something like this:
(Change event on checkbox triggers visibility class on cart div)
$('#tandc').on('change', function(){
if ($(this)[0].checked) {
$('.ct-cart').addClass('ct-cart-visible');
} else {
$('.ct-cart-visible').removeClass('ct-cart-visible');
}
})
/* I would use special classes for showing/hiding, just to give more flexibility on styling, how the cart appears */
.ct-cart {
display: none;
}
.ct-cart-visible {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p style="text-align:center">
<input type="checkbox" name="tandc" id="tandc" value="true"
class="form-control"><label for="tandc"> Please tick box above to confirm you agree with the Terms & Conditions.</label>
</p>
<div class="ct-cart">CART CONTENTS</div>
When the checkbox changes you need to run a function.
if the checkbox is :checked, show() the .ct-cart. Otherwise hide the cart.
$('#tandc').change(function(){
if($(this).is(":checked")){
$(".ct-cart").show();
}else{
$(".ct-cart").hide();
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p style="text-align:center">
<input type="checkbox" name="tandc" id="tandc" value="true" class="form-control"><label for="tandc"> Please tick box above to confirm you agree with the Terms & Conditions.</label>
</p>
<div class="ct-cart" style="display:none;">
Cart
</div>
One further approach:
function toggle() {
// convert the NodeList returned by document.querySelectorAll()
// into an Array, using Array.from():
Array.from(
// using document.querySelectorAll() to find the elements that
// match the selector returned from changed-element's
// custom data-toggle attribute:
document.querySelectorAll(this.dataset.toggle)
// iterating over the Array of nodes:
).forEach(
// using an Arrow function - which avoids changing the
// 'this' - to toggle the class of 'hidden' depending
// on whether the changed-checbox is currently checked
// or not (applying the class-name if the evaluation is
// true, removing it if false):
el => el.classList.toggle('hidden', !this.checked)
);
}
// creating a custom Event (albeit in this case it's the
// browser's 'change' event):
let changeEvent = new Event('change'),
// caching a reference to the relevant element upon which
// the function should fire:
check = document.getElementById('tandc');
// binding the toggle() function (note the deliberate lack of
// parentheses) as the event-handler for the 'change' event:
check.addEventListener('change', toggle);
// firing the 'change' event on page load,
// in order that the relevant element will be
// shown or hidden appropriately:
check.dispatchEvent(changeEvent);
function toggle() {
Array.from(
document.querySelectorAll(this.dataset.toggle)
).forEach(
el => el.classList.toggle('hidden', !this.checked)
);
}
let changeEvent = new Event('change'),
check = document.getElementById('tandc');
check.addEventListener('change', toggle);
check.dispatchEvent(changeEvent);
.ct-cart {
opacity: 1;
transition: opacity 0.5s linear;
}
.hidden {
opacity: 0.1;
}
<p style="text-align:center">
<input type="checkbox" name="tandc" id="tandc" value="true" class="form-control" data-toggle=".ct-cart" /><label for="tandc"> Please tick box above to confirm you agree with the Terms & Conditions.</label>
</p>
<div class="ct-cart">Cart content</div>
References:
JavaScript:
Array.prototype.forEach().
Array.from().
Arrow functions.
Element.classList API.
Element.datalist.
TL;DR:
I use $(..).append(node), but newly added nodes are not considered for inclusion despite them (supposedly) matching jQuery selectors.
Question
I have some code below that uses checkboxes but emulates radio button behavior. In other words, only one checkbox can (validly) be selected at any time. No more than one should be selected.
If you run the example below and click on the first 3 checkboxes, they will behave like radio buttons. Only one will be selected, no matter how many you click.
However, if you Add Point, newly added points will not be considered for the JS even though in theory it should grab them too...
Specifically: You can select the newly added checkbox, and it will be selected in addition to one already selected previously. That is incorrect as only 1 should be selected at any time and all others should be unselected.
What is happening and how can I have newly added nodes be included into jQuery selectors?
$(function() {
//check first box
$("input.duty:first").prop("checked", true);
//clicking unchecked box should check that box
//unchecks all others
$(".duty").on('click', function(event) {
$("input.duty").prop("checked", false);
$(this).prop("checked", true);
});
$("#addCasePoint").on("click", function() {
var newRowIndex = $('#newRowIndex').text();
var template = $('#casePointTemplate').data('template');
template = template.replace(/__index__/g, newRowIndex);
$('#casePointsFieldset').append(template);
$('#newRowIndex').text(++newRowIndex);
return false;
});
//deletes case point
$("#selection").on("click", ".removeCase", function() {
var caseCount = $('#selection .casePointFieldset').length
if (caseCount === 1) return false; //keep at least one row
$(this).closest("fieldset").remove();
return false;
});
});
.casePointFieldset {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="selection">
<fieldset id="casePointsFieldset">
<legend>Case Points</legend>
<div id="pointFieldset">
<fieldset class="casePointFieldset">
<div>
<label><span>Duty:</span> <input name="point[1]" class="duty" value="1" type="checkbox"></label>
</div>
<button class="removeCase">Remove</button>
</fieldset>
<fieldset class="casePointFieldset">
<div>
<label><span>Duty:</span> <input name="point[1]" class="duty" value="1" type="checkbox"></label>
</div>
<button class="removeCase">Remove</button>
</fieldset>
<fieldset class="casePointFieldset">
<div>
<label><span>Duty:</span> <input name="point[1]" class="duty" value="1" type="checkbox"></label>
</div>
<button class="removeCase">Remove</button>
</fieldset>
</div>
<!-- include template -->
<span id="casePointTemplate" data-template="<fieldset class="casePointFieldset"><div><label><span>Duty:</span> <input name="point[__index__]" class="duty" value="1" type="checkbox"></label></div><button class="removeCase">Remove</button></fieldset>">
</span>
</fieldset>
<button id="addCasePoint">Add Point</button>
</form>
The problem is how you're binding to them. The .click function (or .on('click')) basically works like this:
Find all of the currently existing elements which match a selector ($('.your.selector.here'))
Attach an event handler to each of those elements
Notice how I mentioned it binds to ones which already exist? That means it won't bind to newly created ones automatically. However, you can use .on to bind to the parent of those elements then listen for events on a selector. I'll show you what I mean:
$('#addItem').click(function() {
$('.container').append('<button class="item">Item</button>');
});
// Notice that I'm binding to the parent
// then specifying which events from it's children
// I want to listen to (click events from .item elements)
$('.container').on('click', '.item', function() {
console.log("I'm an item");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<button class="item">Item</button>
</div>
<button id="addItem">Add New Item</button>
If you change your on('click' to work like that then you'll have no problems.
Easiest way will be, attaching the event to the document. In the past this was done with the live() method.
$(document).on('click', '.duty', function(event) {
$("input.duty").prop("checked", false);
$(this).prop("checked", true);
});
i am trying to learn and create a jquery which $("#answer") and find all the checkbox inside and check. As an example if checkbox inside #a1 is checked other div (a2,a3,a4) is hidden or other message come out. if i uncheck the #a1 all the div will come out again.
Please enlighten me on the code.
<div id="answer">
<div id="a1">A.<input type="checkbox" name="a1" onclick="cbox()" ></input></div>
<div id="a2">B. <input type="checkbox" name="a2"onclick="cbox()"></input></div>
<div id="a3">C. <input type="checkbox" name="a3"onclick="cbox()"></input></div>
<div id="a4">D. <input type="checkbox" name="a4"onclick="cbox()"></input></div>
</div>
function cbox() {
if (this checkbox is checked) {
target other div inside (#answer) and add .hide()
}
}
2)Is there anyway to add a trigger where i don't need to use onlick="cbox" ?
tq
It's better to use .click() instead of inline javascript onclick.
However, you should use .change() event for input elements instead of click:
$('input[type="checkbox"]').change(function() {
$(this).parent().siblings('div').toggle(!this.checked);
});
Fiddle Demo
Use .change() event instead of .click(). Try this:
$('input[type="checkbox"]').change(function() {
$(this).parent('div').siblings('div').toggle(!this.checked);
});
DEMO
Try this:
$("#answer input").change(function () {
if ($(this).is(":checked")) {
$("#answer input").not(this).each(function () {
$(this).parent().css("display", "none");
})
} else {
$("#answer input").not(this).each(function () {
$(this).parent().css("display", "block");
})
}
});
DEMO