Getting click event from parent container except certain children - javascript

Expected behavior: When I click on the .parent class, an item detail modal will be shown but the modal won't be shown if I click on the .dropdown or any of it's option.
<div class="parent click-for-item-detail">
<div class="dropdown">
Options
<ul class="dropdown-menu">
<li>option-1</li>
<li>option-2</li>
</ul>
</div>
<div class="item-image"><img class="click-for-item-detail" src="image.jpg></div>
<div class="info">
Item title
<div class="click-for-item-detail"> item subtitle</div>
</div>
</div>
So far:
$(".click-for-item-detail").on("click",function(e){
// show the modal if the target itself has been clicked
if(e.target === this) {
$('#itemDetailModal').modal('toggle');
}
});
I have added click-for-item-detail class in every element that should trigger the item detail modal. Is there a better way to achieve this?

It is true what Phong is saying and that works. However, imagine now you had many child elements in your parent all matching that selector. With something like below, you would add an event listener to each of those elements.
$(".info, .item-image").on("click", function(){
console.log("Trigger");
});
While with your first approach you were already very close to only have one listener, no matter how many child elements are in the parent.
Consider following example:
<ul class='parent'>
<li>No</li>
<li>Click</li>
<li>Event</li>
</ul>
$(".parent").on("click",function(e) {
if(!e.target.classList.contains('parent')) {
return console.log('no event')
}
console.log('fire event')
});
This is called event delegation, and you pretty much do this already. Here I am checking if the element, I am clicking on, is indeed of class parent, only then I fire my event.
You can of course do all sorts of checks, for example only the <li> elements.
$(".parent").on("click", (e) => e.target.tagName == 'LI' && console.log('fire event'))
Here check out this example https://codepen.io/bluebrown/pen/xxGVgYd?editors=1111
I would recommend doing a web search for event delegation and event bubbling.

You can specify some selectors to be able to trigger.
Read the following post to have a better understanding.
Event listener for multiple elements - jQuery
$(".info, .item-image").on("click", function(){
console.log("Trigger");
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="parent click-for-item-detail">
<div class="dropdown">
Options
<ul class="dropdown-menu">
<li>option-1</li>
<li>option-2</li>
</ul>
</div>
<div class="item-image"><img class="click-for-item-detail" src="image.jpg"></div>
<div class="info">
Item title
<div class="click-for-item-detail"> item subtitle</div>
</div>
</div>

You can use :not() selector to filter out the element you do not to be clicked:
$('.parent > :not(.dropdown)').click(function(e){
alert('modal');
//show modal
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="parent">
<div class="dropdown">
Options
<ul class="dropdown-menu">
<li>option-1</li>
<li>option-2</li>
</ul>
</div>
<div class="item-image"><img src="image.jpg"></div>
<div class="info">
Item title
<div> item subtitle</div>
</div>
</div>

Related

How can I create an expression that evaluates whether or not a parent div's descendants are active?

Imagine I have a div with a few descendants/children as such:
<div id="parent" tabindex="0">
<h1 tabindex="0"> my Header </h1>
<p tabindex="0"> some text </p>
<ul tabindex="0">
<li tabindex="0"> item 1 </li>
<li tabindex="0"> item 2 </li>
<li tabindex="0"> item 3 </li>
</ul>
</div>
How can I create an expression that checks whether or not a child of the 'parent' div is active/has focus? I'd like to perform some action (ex: console log) if the statement evaluates to true.
I'd imagine it's go something like:
if( document.activeelement === <descendant of 'parent' div>) {
console.log("descendant is active");
}
EDIT: For clarity:
The evaluation should occur as an 'if' statement. The expression should translate like so:
if my active element has a parent with an id of 'parent' then do something.
do you know the id of the parent and the classnames of the children? or will these be dynamic based on what is clicked? if you know the selector of the parent and children, the following will grab an li element that is a deep or immediate child of the #parent element that is active. if it is empty, then none of those tabs are focused
$(#parent li:focus)
using this jquery selector, we're asking for any li child of the #parent element that is active (:focus).
You can use click, keydown, keyuyp events attached to document, $("#parent [tabindex]") selector, .is() , :focus
function checkFocus() {
console.log("descendant is active:"
, $("#parent [tabindex]").is(":focus")
, this.activeElement.tagName)
}
$(document).on("click keydown keyup", checkFocus)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent" tabindex="0">
<h1 tabindex="0"> my Header </h1>
<p tabindex="0">some text</p>
<ul tabindex="0">
<li tabindex="0">item 1</li>
<li tabindex="0">item 2</li>
<li tabindex="0">item 3</li>
</ul>
</div>

Bind the listener to dynamic generate content in HTML

There is a dynamic generate page using jquery like this:
var html = "tab...button..datatable...etc...";
And I generate the page when click on a button
$("btn").on("click",function(){
$("body").append(html);
});
The problem is , all element from generated html does not have event listener, so for the click button /change event I use
$('body').on('change', '.gui-file', function (event) {
However, for the bootstrap element how can I bind the event to the generated element ? e.g. Tab?
Or are there any better way other than binding after generate the html content? Thanks
The tab:
<div class="tab-block mb10">
<ul class="nav nav-tabs nav-tabs-left tabs-border">
<li class="active">
English
</li>
<li class="">
繁體
</li>
<li class="">
简体
</li>
</ul>
<div class="tab-content">
<div id="tab1_1" class="tab-pane active">
</div>
<div id="tab1_2" class="tab-pane">
</div>
<div id="tab1_3" class="tab-pane">
</div>
</div>
Can you please init newly added tab by calling:
$("btn").on("click",function(){
$("body").append(html);
$(".nav-tabs").tab();
});

Trying to get nav to toggle close after li item has been selected

I want the menu to automatically animate closed after an item within the menu has been clicked on. And I want the user to still have the option to toggle the menu again. I managed to get the item to disappear after an item is clicked using $('#overlay').toggleClass(); but now the user no longer has the option to click on the menu again. I've tried googling around but can't find a clear answer. I'm new to JavaScript can someone please point me in the right direction.
Link to example http://codepen.io/anon/pen/KpRmgE
HTML
<div class="button_container" id="toggle">
<span class="top"></span>
<span class="middle"></span>
<span class="bottom"></span>
</div>
<div class="overlay" id="overlay">
<nav class="overlay-menu">
<ul>
<li >Home</li>
<li>Port</li>
<li>Work</li>
<li>Contact</li>
</ul>
</nav>
</div>
<section id="home">
<p>First</p>
</section>
<section id="portfolio">
<p>Second</p>
</section>
<section id="about">
<p>Third</p>
</section>
<section id="contact">
<p>Fourth</p>
</section>
JavaScript
$('#toggle').click(function() {
$(this).toggleClass('active');
$('#overlay').toggleClass('open');
$("nav li").click(function () {
$('#overlay').toggleClass();
});
});
You weren't far off... just a few wrongly placed calls inside the click handler.
Try this:
$('#toggle').click(function() {
$(this).toggleClass('active');
$('#overlay').toggleClass('open');
});
$("nav li").click(function() {
$('#overlay').toggleClass('open');
$('#toggle').toggleClass('active');
});
Forked codepen
You can also do it this way to make your event handler more clear:
$('#toggle').click(function() {
// Adding classes, waiting for a click
$(this).addClass('active');
$('#overlay').addClass('open');
$("nav li").click(function () {
// Clicked! Removing classes
$('#overlay').removeClass('open');
$('#toggle').removeClass('active');
});
});
I personally usually use the addClass and removeClass functions when you are doing that kind of specific action. That helps you avoid small errors that could take long to be seen. :)

Trigger event with same ID elements

I have a menu list that refer to different projects.
Each list item shares its "ID" with a project showcased in a gallery.
<div class="menu">
<ul>
<li id="id1">project 1</li>
</ul>
</div>
<div class="gallery">
<div class="proc id="id1">project 1</div>
</div>
I'd like a jQuery function that :
When a list item from the menu is clicked, gets the project with the same id to do something.
I really don't know where to start from and I'm stuck at that :
<script>
$( "li#id1").click(function() {
$( ".project#id1" ).show();
});
</script>
Many thanks
As the comments said the IDs must be unique and you have missing quote.
You can use data attributes to handle your logic or combination of ids and data attributes.
Try something like this:
HTML
<div class="menu">
<ul>
<li data-project-id="first-project-id">project 1</li>
...
</ul>
</div>
<div class="gallery">
<div class="proc" data-project-id="first-project-id">project 1</div>
</div>
JavaScript
$('.menu li').click(function(){
var targetId = $(this).attr('data-project-id');
$('.proc[data-project-id="' + targetId + '"]').show();
});
The click event is attached to every li item in the element with class .menu.
On click event we extract the data-project-id attribute from the clicked element, find the project elemenet from gallery and show it.
JSFiddle Demo
you can use normal id also (as selector)
HTML
<div class="menu">
<ul>
<li id="first-project-id">project 1</li>
...
</ul>
</div>
<div class="gallery">
<div class="proc" id="first-project-id">project 1</div>
</div>
jQuery
$('.menu li').click(function(){
var targetId = $(this).attr('id');
$('.proc[id="' + targetId + '"]').toggle();
});

Traversing to the element closest to the element clicked jquery

I have this kind of setup in my html
<section class="grp">
<ul class="normal">
<li>Normal Thing <button class="toggle-advanced">toggle advanced</button></li>
</ul>
<ul class="advanced">
<li>This is Advanced</li>
</ul>
</section>
<h1>Another Thing</h1>
<section class="grp">
<ul class="normal">
<li>Normal Thing <button class="toggle-advanced">toggle advanced</button></li>
</ul>
<ul class="advanced">
<li>This is Advanced</li>
</ul>
</section>
How can I toggle the "advanced" ul if I clicked the button in ul.normal?
I tried it like this in coffeescript
$('.normal').on 'click', '.toggle-advanced', (e) ->
$(#).closest('.grp').siblings('.advanced').slideToggle();
since jquery is tagged... using jquery
$('.toggle-advanced').click(function(){
$(this).parents('ul.normal').siblings('ul.advanced').toggle();
});
or
$('.toggle-advanced').click(function(){
$(this).parents('.grp').find('ul.advanced').toggle();
});
these should work unless you aree adding the content dynamically.. use on() if added dynamically
$('.normal').on('click', '.toggle-advanced', function(){
$(this).parents('.grp').find('ul.advanced').toggle();
});
.advanced is not a sibling of .grp element, it is the sibling of the parent .normal element
$(#).closest('.normal').siblings('.advanced').slideToggle();
The javascript equal will be
$('.normal').on('click', '.toggle-advanced', function(){
$(this).closest('.normal').siblings('.advanced').slideToggle();
})
you can try this
$(".toggle-advanced").on('click', function(){
$(this).closest(".normal").siblings('.advanced').slideToggle();
});
this code is jquery based
In Jquery, you can use parent and siblings functions to get to the desired element.
Try this:
$('.toggle-advanced').click(function() {
$('this').parent().siblings().toggleSomething()
});
siblings returns all the siblings for given element, which in your case will always return "advanced" ul.
This should work.
$("ul.normal>li>button").click(function () {
$(this).closest('.normal').siblings('.advanced').slideToggle();
});
Working example: http://jsfiddle.net/riri78/dQcFE/

Categories

Resources