Don't allow child elements to be clicked - javascript

I have elements like this
<div class="parent-component">
<div class="form-group">
<label for="my-input">Label</label>
<input type="text" name="my-input" id="my-input" class="form-control">
</div>
</div>
I have attached a click listener with jQuery on method to the parent as follows
$(document).on("click", ".parent-component", function() {
// ...
})
Where ever I click inside the .parent-component the event listener fires. However, clicking on the input - or any interactive element (links, buttons, inputs) for that matter - it get's active.
How do I prevent any element inside .parent-component from being clicked so that I can have inputs and links inside it which are not able to be clicked?

This is normally desirable behaviour; a click to a child element is also a click to its parent and ancestor elements, in the same way that you can't be in your bathroom without also being in your house.
If you want to guard against child/descendant clicks, however, you can do this:
$(document).on("click", ".parent-component", function(evt) {
if (!$(evt.target).is('.parent-component')) return false;
//beyond here, we can be sure the element was to the parent directly,
//not any children/descendants
})

Another alternative, so that you can use in different places,..
Is for the controls you don't want to propagate events, you could create a class and target this, and tell them not to propagate the events..
The advantage been if you do have some controls that you do want to propagate the events you can leave the class off.
eg..
$(document).on("click", ".parent-component", function(e) {
console.log('click');
});
$(document).on('click', '.no-propagate', function (e) { e.stopPropagation(); });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent-component">
<div class="form-group">
<label class="no-propagate" for="my-input">Label</label>
<input class="no-propagate" type="text" name="my-input" id="my-input" class="form-control">
<span>This still sends clicks to parent</span>
</div>
</div>

pointer-events, credit goes to #Tibos
$(document).on("click", ".parent-component", function(e) {
console.log('click on: ' + e.target.className);
});
.no-click {
pointer-events: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent-component">
<div class="form-group no-click">
<label for="my-input" style="pointer-events: none" >Label</label>
<input type="text" name="my-input" id="my-input" class="form-control" />
<span>This still sends clicks to parent</span>
</div>
</div>

You can check if the target item, which was clicked, has some class, and only then, continue.
$(document).on("click", '.someClass', function(e){
if( e.target.classList.contains('someClass') ) return false;
})

You can do this in several ways
This is just an example on you can exclude child element(s) from parent.
$(document).ready(function(){
$(document).on('click', '.main', function(e){
alert('Parent was clicked');
}).find('.child').on('click', function(){
return false;
});
});
.main{
background: orangered;
color: white;
font-weight: bold;
padding: 10px;
height: 400px;
width: 400px;
padding: 10px;
}
.child{
background: green;
color: white;
margin: auto;
height: 40%;
width: 40%;
padding: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='main'>
Click me and I will fire up something
<div class='child'>
If you click on me I will not fire.....
I am the child you cannot click me
</div>
</div>
Another way
$(document).ready(function(){
$(".main").click(function(){
alert('Parent was clicked');
}).children().click(function(){
return false;
});
});
.main{
background: orangered;
color: white;
font-weight: bold;
padding: 10px;
height: 400px;
width: 400px;
}
.child{
background: green;
color: white;
margin: auto;
height: 40%;
width: 40%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='main'>
Click me and I will fire up something
<div class='child'>
If you click on me I will not fire.....
This is the child you cannot click me
</div>
</div>

Related

Toggle won't stay open

I have images (.rv_button) that are acting as buttons to toggle the div's below (#reveal). I want to hover over the button to open the div but right now I can't get the div to stay open. Can someone help me with this?
jQuery(document).ready(function() {
// Hide the div
jQuery('#reveal').hide();
jQuery('.rv_button').on('mouseenter mouseleave', function(e) {
e.preventDefault();
jQuery("#reveal").fadeToggle()(slow, swing, callback);
jQuery('.rv_button').toggleClass('open');
});
});
Rather than using toggleClass(), on mousenter, remove the open class from all of the buttons and add it to e.target or $(this). And on mouseout just remove it from all the buttons.
Also, remove (slow, swing, callback) or use them as arguments in fadeToggle().
e.g.
jQuery("#reveal").fadeToggle('slow');
And to keep the div to stay open, just wrap the buttons and div in a container and listen for the mouseout event on it instead of the buttons themselves.
$(document).ready(function() {
// Hide the div
$('#reveal').hide();
$('.rv_button').on('mouseenter', function(e) {
e.preventDefault();
$('.rv_button').removeClass('open');
$(e.target).addClass('open');
$("#reveal").fadeIn();
});
$('.container').on('mouseleave', function(e) {
e.preventDefault();
$('.rv_button').removeClass('open');
$("#reveal").fadeOut();
});
});
.container {
width: 400px;
}
#reveal {
width: 400px;
height: 400px;
background-color: beige;
text-align: center;
font-size: 2em;
}
.rv_button {
padding: 1em;
background-color: brown;
width: 400px;
box-sizing: border-box;
}
.open {
background-color: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="rv_button">Button 1</div>
<div class="rv_button">Button 2</div>
<div class="rv_button">Button 3</div>
<div id="reveal">Reveal</div>
</div>

How to make an entire div clickable except a deep level child div?

I want to make an entire div clickable except a child div. This child div is not an immediate child of the div, rather it is in a few level deeper. I would like to dynamically exclude this child div by just passing div id or class name.
I tried to solve it with jQuery ".not()" and ".children()" methods, which works. But its static in a sense that I need to know in which level the div is and need to align the methods accordingly. However, I want something dynamic which will take only the div's class name or id, and find it from the DOM tree and exclude it from the new DOM object chain so that the jQuery ".click" and ".hover" function can be applied on the entire div except that particular div.
I have created a dummy example of my problem. In the example, I want to make the entire div (i.e., id = main1) hyperlinked except the "#d3" div.
Here is my JSFiddle: JSFiddle
Example Code:
HTML:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>
Untitled Document
</title>
</meta>
</head>
<body>
<div class="center border divmain1" id="main1">
<a href="https://www.google.ca" style="display: block">
link
</a>
<p>
Main
</p>
<div class="border-thin divd1" id="d1">
<p>
d1
</p>
</div>
<div class="border-thin divd2" id="d2">
<p>
d2
</p>
<div class="border-thin divd3" id="d3">
<p>
d3
</p>
<div class="border-thin divd4" id="d4">
d4
</div>
<div class="border-thin divd5" id="d5">
d5
</div>
</div>
</div>
</div>
</body>
</html>
CSS:
.border {
border: 5px solid RosyBrown;
}
.border-thin {
border: 2px solid RosyBrown;
}
.divmain1 {
width: 90%;
margin: 0 auto 0 auto;
overflow: hidden;
}
.divd1 {
width: 30%;
float: left;
}
.divd2 {
width: 60%;
float: right;
margin: 0 0 0 3.5%;
}
.divd3 {
margin: auto;
width: 90%;
}
.divd4 {
width: 30%;
}
.divd5 {
width: 30%;
}
jQuery:
// find elements
var main1 = $("#main1")
var d3 = $("#d3")
// handle click and hover pointer
main1.on("click", function(){
window.open('https://www.google.ca');
});
main1.hover(function(){
$(this).css("cursor", "pointer");
});
Could anyone please help me on how to make an entire div clickable and dynamically exclude a child div?
The key thing here is to pass the event object so you can check what is the element actually receiving the click.
Since #d3 contains both #d4 and #d5 I'm assuming you don't want those elements to fire either.
If that's the case, you can use Node.contains() to check if the element is a descendant of your target element.
The Node.contains() method returns a Boolean value indicating whether
a node is a descendant of a given node, i.e. the node itself, one of
its direct children, [...]
If you just want to prevent the action for the element #d3 itself, you don't need to d3.contains and just if (e.target != d3) should do.
// find elements
var main1 = $("#main1")
var d3 = $("#d3").get(0) // Get the HTMLElement
// handle click and hover pointer
main1.on("click", function(e) {
if (!d3.contains(e.target)) {
console.log("I'll open a window");
} else {
console.log("I'm " + e.target.id + " and won't open a window")
}
});
main1.hover(function() {
$(this).css("cursor", "pointer");
});
.border {
border: 5px solid RosyBrown;
}
.border-thin {
border: 2px solid RosyBrown;
}
.divmain1 {
width: 90%;
margin: 0 auto 0 auto;
overflow: hidden;
}
.divd1 {
width: 30%;
float: left;
}
.divd2 {
width: 60%;
float: right;
margin: 0 0 0 3.5%;
}
.divd3 {
margin: auto;
width: 90%;
}
.divd4 {
width: 30%;
}
.divd5 {
width: 30%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="center border divmain1" id="main1">
link
<p>
Main
</p>
<div class="border-thin divd1" id="d1">
<p>d1</p>
</div>
<div class="border-thin divd2" id="d2">
<p>d2</p>
<div class="border-thin divd3" id="d3">
<p>d3</p>
<div class="border-thin divd4" id="d4">d4</div>
<div class="border-thin divd5" id="d5">d5</div>
</div>
</div>
</div>
</body>
</html>
In your jQuery you can run
event.stopPropagation();
within a click event for the div child you don't want to trigger the initial function.
use cancelBubble
for example, to disable your root event on "#d5" div
$('#d5').on('click', function(e){
// stop the event from bubbling.
e.cancelBubble=true
});
I am not much of a fan of jQuery but I can tell you that this can be done with pure JavaScript. All you have to do is to implement an event listener to the top level div and see if the clicked element or it's parent has the targeted class.
Let's take this HTML markup for an example where we will trigger an alert "Target Locked" when someone clicked anything inside divd4 else "General Action"
function HasSelfClassOrParent(element, classname) {
if (element.classList && element.classList.contains(classname))
return true;
return element.parentNode && HasSelfClassOrParent(element.parentNode, classname);
}
let divd2 = document.querySelector(".divd2")
let target = 'divd4'
divd2.addEventListener("click", function(event) {
let isTargetOrChild = HasSelfClassOrParent(event.target, target)
if (isTargetOrChild) {
alert("Target Locked")
} else {
alert("General Action")
}
})
.border {
border: 5px solid RosyBrown;
}
.border-thin {
border: 2px solid RosyBrown;
padding: 20px;
margin-bottom: 10px
}
.divd4{
background: #64B448;
color: #fff;
cursor: pointer;
}
<p>Click on div four and see what happens</p>
<div class="border-thin divd2" id="d2">
<p>I am Div 2</p>
<div class="border-thin divd3" id="d3">
<p>I am Div 3</p>
<div class="border-thin divd4" id="d4">
<p>I am a simple paragraph inside div four</p>
<p>I am a another paragraph inside div four</p>
</div>
<div class="border-thin divd5" id="d5">
I am Div 5
</div>
</div>
</div>

Jquery click on popup div to show another div

The requirement is user can Click on black box to show orange box, and click on orange box to show red box, but the orange box and red box should be hidden
when user click anywhere of the document except the orange box or the
red box itself.
But currently the issue is that we cannot click on orange box to show red box
Would much appreciate if you could help me out, thanks a lot
Demo link: http://plnkr.co/edit/OqlfbmFPKdXx0wDhnLxZ?p=preview
$(function() {
$('#mypop').click(function(e) {
event.stopPropagation();
});
$(document).on('click', '#myclick', function() {
$('#mypop').toggle();
$(document).one('click', function() {
$('#mypop').hide();
});
});
$(document).on('click', '#myclick1', function() {
$('#mypop2').show();
});
$(document).on('click', '#myclick2', function() {
$('#mypop2').show();
});
})()
#mypop {
background-color: orange;
position: absolute;
top: 130px;
left: 50px;
width: 150px;
padding: 15px;
}
.mydiv {
background-color: black;
padding: 30px;
width: 50px;
cursor: pointer;
color: white;
}
#mypop2 {
margin-top: 150px;
background-color: red;
width: 100px;
height: 50px;
padding: 18px;
display: none;
}
#myclick1,
#myclick2 {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="myclick" class='mydiv black-box'>
click me!
</div>
<div id="mypop" style="display:none;" class='orange-box'>
<p>hello world</p>
<div id='myclick1'>BUTTON1</div>
<div id='myclick2'>BUTTON2</div>
</div>
<div id="mypop2" class='red-box'>
Hello World!!!
</div>
try this. I think this is what you are excepting but I'm not sure since you keep editing your question.
Demo Link: http://plnkr.co/edit/n7rdgqTwiFrXtpgoX4TQ?p=preview
$('#myclick1').click(function(){
$('#mypop2').show();
});
$('#myclick2').click(function(){
$('#mypop2').show();
});
You have couple of things mixed up.
The main stop-point was the very first event listener
$('#mypop').click(function(e) {
which is incompatible with the rest of listeners
$(document).on('click','#myclick1',function(e){
after I have changed it to
$(document).on('click','#mypop', function(e){
the other listeners have started working.
Second thing is that for embedded elements (parent-child) you need to stop event propagation, otherwise the parent event is triggered as well (which is not desired)
$(document).on('click','#myclick1',function(e){
e.stopPropagation();
:
});
I have also changed the CSS a bit and added class hide to use instead of styles. Toggling this class is what hides and shows an element.

toggleClass - Parent Sibling Selector - Issue

Just having a couple of issues, with the below script I've made.
It works perfectly in terms of toggling the form panels, however when i then start to interact with the 'Active' panel (ie click a input field), the active class is removed from its parent element, thus minimizing the panel.
$(function () {
$('.options-list li').click(function () {
$(this).toggleClass('active');
$(this).parent().children('li').not(this).removeClass('active');
});
});
Is there a way I can restrict the toggle function to only the title contents?
https://jsfiddle.net/os883y47/
I think its due to the 'Title' within the <'li'> not having its own containing element, so I wrapped the text within a <'span'> element & this appears to fix the form minimising issue however now the 'active' class isn't getting removed (assuming its now a child selector issue??).
https://jsfiddle.net/avk7e30a/
Any help would be greatly appreciated.
This is happening because of event bubbling to the li. The click events on the input are bubbled up to the li element and the event handler is executed again. To stop this from happening, use event.stopPropagation() on child elements event handlers.
Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
Updated Fiddle
Add following code
$('.active-panel').click(function (e) {
e.stopPropagation(); // Stop event from bubbling up
});
$(function() {
$('.options-list li').click(function() {
$(this).toggleClass('active');
$(this).parent().children('li').not(this).removeClass('active');
});
$('.active-panel').click(function(e) {
e.stopPropagation();
});
});
.options-list {
border: 1px solid #d5d6d7;
padding: 0;
margin-bottom: 30px;
}
.option {
list-style: none;
border-bottom: 1px solid #dadada;
font: 16px/56px avenir_65regular !important;
color: #333;
}
.options-list .option.active {
color: #004ebc;
}
.options-list .option.active:before {
background-color: #004ebc !important;
border: 5px solid #83ace0 !important;
}
.options-list .option:before {
content: "";
background-color: #fff;
border-radius: 16px;
border: 5px solid #004ebc;
height: 18px;
margin: 0 10px;
width: 18px;
position: relative;
top: 3px;
box-sizing: border-box;
display: inline-block;
}
.panel {
height: 0;
overflow: hidden;
background: #f9f9f9;
border-top: 1px solid #d5d6d7;
transition: all 0.5s linear;
transition: height 0.25s ease-in-out;
/* visibility: hidden; */
/* opacity: 0; */
/* transition: visibility 0s, opacity 0.5s linear; */
}
.option.active > .panel {
/* visibility: visible; */
/* opacity: 1; */
height: 100%;
padding: 25px 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<ul class="options-list">
<li class="option active">FORM FIELD 1
<div class="panel active-panel">
<div class="form-field">
<label class="form-label black">Sub Field</label>
<input class="form-input" type="text" />
</div>
<div class="form-field flt">
<label class="form-label black">Sub Field</label>
<input class="form-input half" type="text" />
<input class="form-input half" type="text" />
</div>
<div class="form-field flt">
<label class="form-label black cvc">Sub Field</label>
<input class="form-input half" type="text" />
</div>
</div>
</li>
<li class="option">FORM FIELD 2
<div class="panel"></div>
</li>
<li class="option">FORM FIELD 3
<div class="panel"></div>
</li>
</ul>
Read: What is event bubbling and capturing?
HTML is the same.
JQuery
$(function() {
$('.options-list li').click(function(){
$(this).closest('.options-list').find('.active').removeClass('active');
$(this).addClass('active');
});
});
Here is a fiddle : https://jsfiddle.net/os883y47/2/
Change your code to following
$(function() {
$('.options-list li').click(function(e){
if (e.target === this) {
$(this).toggleClass('active');
$(this).parent().children('li').not(this).removeClass('active');
}
});
});
This is because, you added click event to the parent, so even when you click its children the event get triggered. So a validation is required to confirm it is parent element
You may want to prevent the click-event on the panels:
JavaScript
$('.options-list li .panel').click(function(evt){
evt.preventDefault();
return false;
});
JSFiddle
I would add the following code as the first statements in your handler, so it only continues if the click was on a direct child (li) of the .options-list element:
$('.options-list li').click(function(e){
if (!$(e.target).parent().is('.options-list')) {
return;
}
...
Here is the fiddle.

how to make an image work as a check box?

I am working on phone-gap application in dream-weaver
I have 2 divs .pics and .cover
<div class="pics">
<div class="cover"></div>
</div>
the main idea is to change the colour of the cover div and toggle a JS variable between true and false
var checked=false;
$('.pics').click(function(){
CheckToggle();
});
function CheckToggle(){
if(checked==false){
checked=true;
$('.cover').css({"background":"rgba(255,255,255,.5)"});
}
else
checked=false;
}
I click on .pics and nothing happens
I think there is an error in the jquery code
This is what I used after all
$(function(){
$( "#item1" ).bind( "tap", PicCheck );
var checked;
var choosen="#item1";
checked=$(choosen).attr('pcheck');
function PicCheck( event ){
if(checked=="false"){
$(choosen).toggleClass("selected");
checked="true";
}
else if(checked=="true"){
$(choosen).toggleClass("selected");
checked="false";
}
$(choosen).attr('pcheck',checked);
}
});
With some css you can implement a checkbox and radio buttons with pictures. Try this :
<div>
<input id="input-1" class="img-checkbox" type="radio" name="selectTipo">
<label for="input-1" class="">
<img src="http://upload.wikimedia.org/wikipedia/commons/thumb/6/61/HTML5_logo_and_wordmark.svg/128px-HTML5_logo_and_wordmark.svg.png">
</label>
<input class="img-checkbox" type="radio" id="input-2" name="selectTipo">
<label for="input-2">
<img src="http://www.javatpoint.com/images/javascript/javascript_logo.png">
</label>
And in your css :
input.img-checkbox[type=radio], input.img-checkbox[type=checkbox] {
display: none;
}
img{
height:100px;
}
input.img-checkbox[type=radio]+label, input.img-checkbox[type=checkbox]+label {
border: 10px solid transparent;
display: inline-block;
border-radius: 10px;
}
input.img-checkbox[type=radio]:checked+label, input.img-checkbox[type=checkbox]:checked+label {
border: 10px solid #C6ECED;
display: inline-block;
}
See the result in the follow jsfiddle
I'd skip the Javascript and use a label element and the :checked selector.
#example {
visibility: hidden;
width: 0;
}
label {
color: purple;
}
#example:checked + label {
background-color: red;
color: white;
}
The HTML would be like this:
<input id="example" type="checkbox" name="example" value="true">
<label for="example">Example</label>
With this approach you wouldn't need to worry about tracking the checked variable and you can just figure it out normally.
Here's a demo: http://jsbin.com/cirali/1/edit?html,css,output
It is usually most convenient to use additional class for your purpose.
Here is a simple example:
var checked = false;
$('.pics').click(function() {
CheckToggle();
});
function CheckToggle() {
$('.cover').toggleClass('selected');
checked = $('.cover').hasClass('selected');
}
.cover {
background: red;
}
.cover.selected {
background: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="pics">
<div class="cover">test</div>
</div>
Edit:
Since you are using jQuery mobie, you might want to try the vclick or tap events instead of the regular click event.
Depending on how you have the elements styled, it might be better to put the action on the .cover element... If the child element .cover is the exact same height and width of the parent element .pics you wont be able to click on .pics

Categories

Resources