toggleClass - Parent Sibling Selector - Issue - javascript

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.

Related

CSS-based tabs (also Javascript if necessary)

I have an HTML like the below format:
<div class="parent1">
<div class="child1"></div>
<div class="child2"></div>
<div class="child3"></div>
</div>
<div class="parent2">
Content here
</div>
Where Child 1/2/3 are tabs. Upon clicking one, the content will get active and a class active is added there.
I want to make the parent2 class visible (display block) only if Child 2 is active. I have tried some CSS which are not working.
Is there any possible script available for that?
Thank you.
In Jquery,
$(".child2").hasClass("active")?($(".parent2").css("display","block")):($(".parent2").css("display","none"))
A javascript onclick function will work for this.
<style>.nodisplay{display: none;}</style>
<div class="parent1">
<div id='child1' onclick='show(this)' data-id='parent2' class="child1">Parent2</div>
<div id='child2' onclick='show(this)' data-id='parent3' class="child2">Parent3</div>
<div id='child3' onclick='show(this)' data-id='parent4' class="child3">Parent4</div>
</div>
<div id='parent2' class='nodisplay'>
Content here
</div>
<div id='parent3' class='nodisplay'>
Content here
</div>
<div id='parent4' class='nodisplay'>
Content here
</div>
<script>
function show(div) {
var id1 = div.getAttribute('data-id');
var x = document.getElementById(id1);
if (x.style.display === "block") {
x.style.display = "none";
} else {
x.style.display = "block";
}
}
</script>
First I set the display of parents 2, 3, & 4 to none with CSS. next I add an onclick function to each child div and specify the data I want my script to pick up.
Then in my function; it will either collect 'parent2', parent3', or 'parent4' depending on which div was clicked, then assigns it the variable of id1. Next I create a variable 'x' to toggle between showing the div or not.
I hope this helps you understand using javascript to manipulate CSS a little better. Have a great day.
There are several ways to do it, you can try with jQuery show() and hide() , check here:
UPDATE: Using display block
You can do this:
//Register click listener:
$(".child2").click(function() {
//Check if the class is added
if($(".child2").hasClass("active")){
//Set display block
$('.parent2').css('display', 'block')
}
});
Both css('display', 'block') and show() will work
This is a purely CSS-based tabs implementation:
.parent {
font-size: 0;
}
input[type=radio] {
display: none;
}
input[type=radio]+label {
border: 4px solid #f0f0f0;
display: inline-block;
font-size: 16px;
padding: 10px;
min-width: 100px;
text-align: center;
transition: all .2s ease;
}
input[type=radio]:checked+label {
background-color: #a00;
color: #fff;
}
.tab-content {
background-color: #f0f0f0;
position: absolute;
height: 500px;
width: 500px;
opacity: 0;
transition: all .3s ease-in-out;
font-size: 16px;
padding: 15px;
}
input[type=radio]:checked ~.tab-content {
transition: all .6s ease-in-out .2s;
}
#tab1:checked~.tab1 {
opacity: 1;
}
#tab2:checked~.tab2 {
opacity: 1;
}
#tab3:checked~.tab3 {
opacity: 1;
}
<div class="parent">
<input type="radio" name="tabs" id="tab1" checked><label for="tab1">Tab 1</label>
<input type="radio" name="tabs" id="tab2"><label for="tab2">Tab 2</label>
<input type="radio" name="tabs" id="tab3"><label for="tab3">Tab 3</label>
<div class="tab-content tab1">Content for Tab 1...</div>
<div class="tab-content tab2">... here's content for Tab 2, ...</div>
<div class="tab-content tab3">... and, last but not least, here's Tab 3 content.</div>
</div>

Don't allow child elements to be clicked

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>

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

Side panel to close when I close anywhere outside it

I have left panel which slides in as I press the menu button (it is a mobile version). When the left panel slides in, I want it to close when I click anywhere else except the left panel itself. The jquery I made is this:
$(document).ready(function(){
$('.menu').click( function() {
if ($('.sidemenuu').hasClass('hidden')) {
$('.sidemenuu').animate({left:"0%"},255);
$('.sidemenuu').removeClass('hidden');
return true;
}
else {
if($('.sidemenuu').css("left","0")){
alert('jkk');
$('html').click(function() {
$('.sidemenuu').animate({left:"-80%"},255);
});
}
$('.sidemenuu').addClass('hidden');
$('.sidemenuu').animate({left:"-80%"},255);
}
});
$('.close').click(function(){
$('.sidemenuu').animate({left:"-80%"},255).addClass('hidden');
//$('.sidemenuu').addClass('hidden');
});
$('.sidemenuu').click(function(e){
});
});
html:
<div class="sidemenuu hidden">
<div class="close"></div>
<div class="over-y-auto">
<div data-role="content">
<div id="getVerificationSearchList" >
<button onClick="getVerificationSearchList()">Verification Data</button>
</div>
<div id="getNewHomeLoan" >
<button onClick="getNewHomeLoan()">New Home Loan</button>
</div>
<div id="getNewLoan" >
<button onClick="getNewLoan()">New Loan</button>
</div>
<div id="getContactRecording" >
<button onClick="getContactRecording()">Contact Recording</button>
</div>
<div id="getCPU" >
<button onClick="getCPU()">CPU</button>
</div>
<div id="getphotoupload" >
<button onClick="getimageupload()">Photo Upload List</button>
</div>
<div id="getdocumentupload" >
<button onClick="getdocumentupload()">Document Upload List</button>
</div>
<div id="getreceiptupload" >
<button onClick="getreceiptupload()">Receipt List</button>
</div>
</div>
</div>
</div>
css:
.sidemenuu{ background-color: #181818;
height: 100%; left: -40%;
position: relative;
box-shadow: 9px 0 10px #303030;
position: fixed;
border-right: solid 1px #444;
padding: 1%;
width: 75%;
left: -80%;
z-index: 10;}
.over-y-auto{ overflow-y: auto; height: 100%;}
.sidemenuu button{ background-color: #141414;
border-bottom: solid 1px #000 !important;
border-left: 0;
border-right: 0;
border-top: solid 1px #171717 !important;
color: #565656;
height: 55px;
width: 98%;
font-size: 18px;
}
.sidemenuu button:hover{ background-color: #202020; box-shadow: 0 0 7px #000 inset;}
.close { background: url("img/close.png") no-repeat scroll center 5px #252525;
border: solid 1px #333;
border-radius: 4px;
cursor: pointer;
height: 40px;
margin: 0 auto 19px;
padding: 0;
width: 73px;
}
.menu{ cursor: pointer; left: 0;
position: absolute;}
fiddle is here: http://jsfiddle.net/cLJVV/
This is a fairly common and potentially tricky problem. You'd like to bind to any click 'outside' your element, but DOM events don't work that way. Every click is inside something, and that's what's going to receive the event and bubble it up the DOM.
So, the way to solve this is to listen to clicks on the document itself, and check whether those clicks are inside the element you want to detect clicks outside of (your sidebar). If the clicks made it all the way to the document without passing through your element, they are outside. The simplest function to check for that would look like this:
var openSidebar = function(){
$('.sidemenuu').removeClass('hidden').animate({left:"0%"},255);
}
var closeSidebar = function(){
$('.sidemenuu').addClass('hidden').animate({left:"-80%"},255);
}
$('.menu').click( function(event) {
event.stopPropagation();
openSidebar();
});
$(document).click( function(event){
if ( !$(event.target).closest('.sidemenu').length ) {
closeSidebar();
}
});
See updated fiddle here: http://jsfiddle.net/cLJVV/2/
Note one really important thing: in the .menu click function, the first line is calling event.stopPropagation(). This call stops the event from continuing to bubble up to the root of the document.
Recall that the click binding on the document is going to catch all clicks, and any clicks that didn't originate inside your side menu element will call the function to close it. So, if you have an element that is outside and you don't want that element to trigger your sidemenu to close, you need to stop propagation of clicks on that element. In this case, that's what I did to the menu button on your fiddle.
Hope this helps!
Why not use the focusout event handler.
The focusout event is sent to an element when it, or any element inside of it, loses focus. This is distinct from the blur event in that it supports detecting the loss of focus on descendant elements (in other words, it supports event bubbling).
Example:
$('.close').click(function () {
$('.sidemenuu').animate({
left: "-80%"
}, 255).addClass('hidden');
//$('.sidemenuu').addClass('hidden');
});
$('.sidemenuu').focusout()(function () {
$('.sidemenuu').animate({
left: "-80%"
}, 255).addClass('hidden');
//$('.sidemenuu').addClass('hidden');
});
You can also use a separate function for both as they do the same thing.
Example:
$('.close').on( "click", closeSidemenu )
$('.sidemenuu').on( "focusout", closeSidemenu )
function closeSidemenu() {
$('.sidemenuu').animate({
left: "-80%"
}, 255).addClass('hidden');
//$('.sidemenuu').addClass('hidden');
}
Either way is valid, but the second one is easier to maintain, requires less code, and is easier to troubleshoot.

Changing image within div when clicked

Spent a couple of days on this now and need some guidance. I have a toggle with an image within the div. Basically when the div is clicked the image within it should change to a different image.
Here is a link to the jsfiddle, so you can see the image at the top which should change once the whole toggle area is clicked.
http://jsfiddle.net/VLe8g/
Also here is the code
HTML
<div class="toggle-wrap">
<div class="trigger">
<div class="one-third"><img src="http://placehold.it/200x200" /></div>
<div class="two-thirds column-last">This is where the heading goes <br />
This is where the description goes<br />
Toggle Open</div>
</div>
<div class="toggle-container">
<div class="one-third">First column This is where the heading goes This is where the heading goes</div>
<div class="one-third">Second column This is where the heading goes This is where the heading goes</div>
<div class="one-third column-last">Third column This is where the heading goes This is where the heading goes</div>
</div>
</div>
CSS
.toggle-wrap {
float: left;
width: 100%;
margin-bottom: 5px;
}
.trigger {}
.trigger a {
display: block;
padding: 10px;
padding-left: 15px;
text-decoration: none;
font-weight: bold;
color: #1D1D1B;
-webkit-transition-duration: 0s;
-moz-transition-duration: 0s;
-o-transition-duration: 0s;
background: url(tobeadded) no-repeat right 15px #F3F3F3;
}
.trigger.active a {
background: url(tobeadded) no-repeat right -20px #F3F3F3;
}
.toggle-container {
overflow: hidden;
float: left;
padding: 15px 15px 0 15px;
}
.one-third, .two-thirds {
display: inline;
float: left;
margin-right: 4%;
}
.one-third {
width: 30.66%;
}
.two-thirds {
width: 64%;
}
JAVASCRIPT
$(".toggle-container").hide();
$(".trigger").toggle(function(){
$(this).addClass("active");
}, function () {
$(this).removeClass("active");
});
$(".trigger").click(function(){
$(this).next(".toggle-container").slideToggle();
});
Hope you guys can help me out.
Thanks.
Demo here
Try this:
$(".toggle-container").hide();
$(".trigger").toggle(function () {
$(this).addClass("active");
$(".trigger").find('img').prop('src', 'http://jsfiddle.net/favicon.png');
}, function () {
$(this).removeClass("active");
$(".trigger").find('img').prop('src', 'http://placehold.it/200x200');
});
$(".trigger").click(function () {
$(this).next(".toggle-container").slideToggle();
});
$(this).find("img").attr("src", "http://placehold.it/400x400");
will change the image from a 200x200 to a 400x400. You can add a class to both of them (i.e. class=small, class=big) which jQuery can use to identify which one is currently being displayed and toggle between them.
assign an id to image tag like i did
<img id="test" src="http://placehold.it/200x200" />
and use the following code:
$(".toggle-container").hide();
$(".trigger").toggle(function(){
$(this).addClass("active");
$('#test').attr('src','http://placehold.it/200x200');
}, function () {
$(this).removeClass("active");
$('#test').attr('src','https://fbcdn-dragon-a.akamaihd.net/hphotos-ak-ash3/s200x200/851558_201013993381868_2094147002_n.png');
});
$(".trigger").click(function(){
$(this).next(".toggle-container").slideToggle();
});
Add the id attribute to your img, and then change the src attribute every time the toggle handler is executed.
The img definition should something like this:
<img id="myImage" src="http://placehold.it/200x200" />
and your toggle handler should look like this:
$(".trigger").toggle(function(){
$(this).addClass("active");
$("#myImage").attr('src', 'http://placehold.it/some_other_image');
}, function () {
$(this).removeClass("active");
$("#myImage").attr('src', 'http://placehold.it/200x200');
});

Categories

Resources