I have a checkbox which will allow the users to show/hide certain features. So I have 2 divs with separate IDs and one div is added directly to my code and the second div is dynamically added through a plugin with the CSS display:none.
$(function() {
$("#chkstatus").click(function() {
if ($(this).is(":checked")) {
$("#dv").show();
$("#Add").hide(); //dynamic div
} else {
$("#dv").hide();
$("#Add").show(); //dynamic div
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="dv" class="forgo">
<h1>Benefits</h1>
<p></p>
</div>
<!-- The below code is not visible in the page source but visible in inspect element -->
<div id="Add" class="form-group" style="display:none">
<input class="btn-block button" type="button" style="" value="Upload File">
</div>
The problem is that the show/hide is working perfectly to the #dv but nothing happens to #Add. It always stays hidden.
Can someone let me know how can make the show/hide work for the dynamically added div?
Instead of binding the event listener to the dynamically created div you should add an eventlistener on the parent (say <div id='cont'></div> ) which is ofcourse static in nature .
Say the event we are listening to is click, now whenever you click the parent you have the reference to the specific div (even if there a lot of dynamic divs like this) as a target attribute of the event. which you can find by digging the output in console log.
Why and How ??
This is because of event delegation and event bubbling i.e. the event bubbles up to the parent div and keep on bubbling up to the body in DOM tree.
So for this case, as the event is click( checkbox ) which is on some different element (no parent child relation with dynamically added div) so we can use trigger to fire our own custom event on the parent div.
$(document).ready(function () {
$("#cont").on('myEvent1',function(){
$(this).find('#dv').show();
$(this).find('#Add').hide();
});
$("#cont").on('myEvent2',function(){
console.log($(this)); // This will o/p the #cont div containing both the static and dynamic div in it.
$(this).find('#dv').hide();
$(this).find('#Add').show();
});
$("#chk").change(function () {
if ($(this).is(":checked")) {
console.log($(this)); // This will o/p the checkbox element
$("#cont").trigger('myEvent1');
}
else {
$("#cont").trigger('myEvent2');
}
});
});
You can try to mold it for your exact purpose and can also use toggle to reduce the LOC.
Related
I have two screens on the page. Every screen has 5 tables, there is only one table that can be seen. I want to change the visible table with these buttons. There are 2 buttons (previous, next) for each screen.
Here is my Javascript code to buttons:
document.querySelector('.screen.show .screen-table-buttons .next').onclick = function(){
...
}
This code works when the page is loaded the first time, but when added the show class to other screens, and I want to use it, it's not working. I want to use these buttons when the screen parent has a show class.
I changed the show class, added it to other screens, reloaded the page, and then other buttons worked on the other screen, but the first buttons didn't work.
So, I just want to use all buttons when the div parent has the show class. If the parent does not have the show class, don't work, If has it, just do it.
As mentioned in the comments this is a good case for event delegation - a single listener is attached to the document (or relevant ancestor) and functions are called based on target attributes.
Here it is attached to the document and it first checks if the clicked target has an ancestor with class screen.show using closest() if it does we check the classList of the target using classList.contains() to trigger the relevant function call.
function next_fn() {
console.log('next');
}
function previous_fn() {
console.log('previous');
}
document.addEventListener('click', (event) => {
if (event.target.closest('.screen.show')){
if (event.target.classList.contains('next')) {
next_fn();
}
if (event.target.classList.contains('previous')) {
previous_fn();
}
}
});
<div class='screen'>
<h6>Screen no-show (buttons won't trigger)</h6>
<button type='button' class='next'>Next</button>
<button type='button' class='previous'>Previous</button>
</div>
<div class='screen show'>
<h6>Screen show (only these buttons work)</h6>
<button type='button' class='next'>Next</button>
<button type='button' class='previous'>Previous</button>
</div>
<div class='not-screen'>
<h6>Not-screen (buttons won't trigger)</h6>
<button type='button' class='next'>Next</button>
<button type='button' class='previous'>Previous</button>
</div>
As Teemu said in the comment, the way you're binding the click event means that you're binding the click event to the button that is already visible (i.e. the one that has the show class at the moment the line you've put in the question is hit) - it isn't designed to cater for elements that may or may not exist at some point in the page lifecycle.
You'll either need to rebind the click event each time you switch the show class, or you can bind the event regardless of the show class.
In order to rebind the event each time, you'd be better off pulling the function out into its own area - something like this:
document.querySelector('.screen.show .screen-table-buttons .next').onclick = NextClicked
function NextClicked() {
... do the normal click event stuff, and move the show class to the other screen
document.querySelector('.screen.show .screen-table-buttons .next').onclick = NextClicked
}
Alternatively, you could bind the click event once and do a check to see whether the one clicked is the right one - something along these lines:
document.querySelector('.screen .screen-table-buttons .next').onclick = function(e){
if (e.target.parentElement.parentElement.hasClass('show')){
...
}
}
I'm new here, and in Jquery ...
I am using Wordpress to create a website and I have a Jquery function for opening cards, these cards have a plus button, and clicking that button opens a description of the card ...
So far so ok, but all the cards have the same classes (on the button, and the description) and pulling it on the page I need to use them by clicking on one of the buttons it opens all the descriptions of the other cards ... can i make it open only the card description of the button i clicked?
Code:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
$(this).ready(function(){
$(".abrir-btn").click(function(){
$(".conteudo-div").show(200);
$(".abrir-btn").hide();
$(".fechar-btn").show();
$(".listing-nucleados").css("background-color", "#FFE500");
$(".listing-nucleados").css("border-color", "#fff");
});
$(".fechar-btn").click(function(){
$(".conteudo-div").hide(200);
$(".abrir-btn").show();
$(".fechar-btn").hide();
$(".listing-nucleados").css("background-color", "#fff");
$(".listing-nucleados").css("border-color", "#EBEBEB");
});
});
</script>
Assuming, the buttons as well as the .listing-lucleados are both wrapped inside a parent element (let's call it .my-parent here). You can do the following:
$(this).ready(function(){
$(".abrir-btn").click(function(){
$(this).hide();
var parent = $(this).parents('.my-parent');
parent.find(".conteudo-div").show(200);
parent.find(".fechar-btn").show();
parent.find(".listing-nucleados").css("background-color", "#FFE500").css("border-color", "#fff");
});
$(".fechar-btn").click(function(){
$(this).hide();
var parent = $(this).parents('.my-parent');
parent.find(".conteudo-div").hide(200);
parent.find(".abrir-btn").show();
parent.find(".listing-nucleados").css("background-color", "#fff").css("border-color", "#EBEBEB");
});
});
Basically, what this does is going up the DOM tree to the parent element wrapping the show/hide buttons, as well as the list to show/hide. Then, from the parent element, find its descendants (I'm not saying direct children, because I do not know that much about your HTML structure) and apply the operation only to elements of this class inside the parent element.
In the function performed after clicking the button find a common ancestor of both elements - the button and the description - using closest().
Having an ancestor, find in it elements with the class .abrir-btn, .fechar-btn or .conteudo-div.
Example HTML:
<div class="content-outer">
<!-- the order inside is not important -->
<button class="abrir-btn" >show</button>
<button class="fechar-btn" >hide</button>
<div class="conteudo-div">...</div>
</div>
$(this).ready(function(){
$(".abrir-btn").click(function( event ){
var parent = $(event.target).closest(".content-outer");
if ( !parent.length )
return;
parent.find(".conteudo-div").show(200);
parent.find(".abrir-btn").hide();
parent.find(".fechar-btn").show();
parent.find(".listing-nucleados").css("background-color", "#FFE500").css("border-color", "#fff");
});
});
.PopBgd is 100% of the screens size with another div .PopUp contained within .PopBgd and appearing on top of it.
Clicking on .PopBgd gives the desired effect of Hiding. However clicking anywhere in PopUp also runs the fadeOut part of the script below.
QUESTION
How to prevent the fadeOut part of the script from triggering though overlying divs?
$('.BtnPop').click(function(e) {
e.preventDefault();
$($(this).data('popup')).fadeIn();
$('.PopClose, .PopBgd').click(function() {
$('.PopBgd').fadeOut();});
});
ANSWER
<button type="button" class="BtnPop" data-popup=".Pop1">CLICK</button>
<div class="Pop1 PopBgd">
<div class="PopUp">
<a class="PopClose">×</a>
<div>Content</div>
</div>
</div>
$('.BtnPop').click(function(e) {
e.preventDefault();
$($(this).data('popup')).fadeIn();
});
$('.PopClose, .PopBgd').click(function() {
$('.PopBgd').fadeOut();});
$('.PopUp').click(function(e) {
e.stopPropagation();
});
NEW QUESTION
How to use StopPropogation when the target div's name is unknown?
What I have tried above does not work.
I resolved my additional problem by simply adding a second class name that was static to the desired div to allow stopPropogation to work as normal.
$('.Pop').click(function(e) {
e.stopPropagation();
});
.stopPropagation() "Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event."
I have the following HTML code:
<div id='parentDiv'>
<div class='firstDiv'>
<div class='firstDivChild1'></div>
<div class='firstDivChild2'>
<div class='firstDivChild2_Child1'></div>
<div class='firstDivChild2_Child2'></div>
</div>
</div>
<div class='secondDiv'>
<div class='secondDivChild1'>
<div class='secondDivChild1_child'>
<div class='secondDivChild1_child_child'></div>
</div>
</div>
</div>
</div>
Now my requirement is when I click on any div I want to get an top most parent Id (i.e. parentDiv). Presently I'm using the below script to get parent Id:
<script type='text/javascript'>
$('div').click(function(e){
var parentDivId = (e.target).parentNode.id;
alert(parentDivId );
});
</script>
but it doesn't work. Can anyone correct this code to reach my requirement?
If that parent DIV is unique across document, then you just can refer to it by ID, i.e. $('#parentDiv'), but if it's not, then you should change your HTML and add to parentDiv some class (i.e. parentDiv), and you'll be able to refer to it by this expression $(this).parents('.parentDiv:first');
$('div').click(function() {
alert($(this).parents('div').last().attr('id'));
return false;
});
Live DEMO
then use the natural power of event bubbling. any descendant clicked will bubble up the event upwards (hence bubble) and will act as if the parent is clicked. so adding a click handler to the parent also does the same thing.
$('#parentDiv').on('click',function(){
var id = this.id
});
Try this little function :
$.fn.root = function() {
var $all = $( this[0] ).parents();
// omit "html", "body" and one index to the last item;
return $all.slice( $all.length - 3, $all.length - 2 );
};
Sample Usage :
$('input').click(function() {
alert($(this).root().prop('id'));
});
Simple working example using your HTML here
It is still not completely obvious what you're asking for, but based on a few of your comments, here's my best guess.
Using event bubbling, you can examine all clicks in your document and you then determine where the click originated with e.target and you can then figure out whether that click originated in your div tree or elsewhere:
$(document).click(function(e) {
// determine if click was in our div tree or not
if ($(event.target).closest("#parentDiv").length) {
// click was in our parentDiv tree
} else {
// click was not in our parentDiv tree
}
});
Regardless of where the click was located, you can get the top of your div tree id="parentDiv" at any time with this with this jQuery:
$("#parentDiv")
If, you just want the top-most div that is above what is clicked, no matter where the click is in the document, you can use event bubbling like this to get that:
$(document).click(function(e) {
e.stopPropagation();
var topMostDiv = $(e.target).parents("div").last();
// do whatever you want with topMostDiv here
});
Basicllay i have a div with a class called .li-level-1, and inside that i have differnt ul's with lists. i Have it set up so when you click on a li-level-1 div displays the ul's and li's inside that div by animating a drop down and when you click on the next one it closes the one previously opened and slidesDown the next one.
the only thing is the a links that are inside the div's seem to trigger the slideUp/Down on level-1 and animation as well.
any Suggestions?
$('.sitemap_page .li-level-1').each(function(){
$(this).find('ul.ul-level-2').hide();
$(this).click(function(){
var this_list = $(this);
this_list.parent().find('.open').each(function(){
$(this).slideUp(function(){
this_list.find('ul.ul-level-2').addClass("open").slideDown();
}).removeClass('open');
});
if(this_list.find('ul.ul-level-2.open').length == 0) {
this_list.find('ul.ul-level-2').addClass("open").slideDown();
}
});
});
That's because of event bubbling: the click event raised on the <a> elements bubble up to their containing <div> and cause your event handler to execute.
One way to work around that problem would be to use event.target to determine the event's origin, and only perform the sliding animations if the event did not originate on a link:
$(this).click(function(event) {
if (!$(event.target).is("a")) {
var this_list = $(this);
this_list.parent().find('.open').each(function() {
$(this).slideUp(function() {
this_list.find('ul.ul-level-2').addClass("open").slideDown();
}).removeClass('open');
});
if (this_list.find('ul.ul-level-2.open').length == 0) {
this_list.find('ul.ul-level-2').addClass("open").slideDown();
}
}
});
The problem is with event bubbling as sugested by Frederic. The other possible solution is to divide your div into title and content divs. Hold data in content and check click on title (not on the parent list). This means rebuilding the handler but the code will be clearer and it won't depend on event.target.