Launch event on click of element but on things inside element - javascript

Hello I made drawer which appears when you click on it and then expands it's width, after second click, it back to it's minimalized form, inside this drawer I have table with checkboxes etc which I will use later to filter things. Thing is that if I click on checkbox inside the table, drawer is hiding. How to do it that event which allow for toggling of width of drawer would work only if I click on it except place where is table? As far as I know it should do something with stopPropagation but somehow I was unabled to implement it in working form.
<div class="filter_drawer" onclick="show_stat()">
<Table class="stat_table">
...some content
</Table>
</div>
function show_stat() {
event.stopPropagation()
var stats = document.querySelector('.filter_drawer')
var table = stats.querySelector('.stat_table')
var panels = document.querySelector('.main_container')
stats.classList.toggle('expanded_stat')
table.classList.toggle('show')
panels.classList.toggle('expanded_stat_panel')
}

Attach the listener to the element properly using Javascript instead, and then you can check if the event.target is the .filter_drawer element. If so, then it was a click directly on the element, and not one of its descendants:
document.querySelector('.filter_drawer').addEventListener('click', (e) => {
if (e.target.matches('.filter_drawer')) {
showStat();
}
});
(If the click was on a descendant element, and not the filter_drawer itself, then the e.target test won't match)
No need for stopPropagation.

Related

How to change image when two buttons are clicked?

I want to make jQuery script where I will have 10 buttons all with different colors and after user clicks on two different buttons, combination of the clicked buttons colors will be made and switch the image frame with already prepared images based on color combinations.
My question is how to put conditions for two buttons(or links) clicked.
switch me
<img src="http://placehold.it/333/fe3/img/picture2.jpg" id="bg" />
$(function() {
$('.menulink').click(function(e){
e.preventDefault();
$("#bg").attr('src',"http://placehold.it/333/3ef/img/picture1.jpg");
});
});
I want to achieve something like this but I want image to change when two buttons (or links) are clicked.
http://jsfiddle.net/maniator/Sevdm/
provided you wanted to make sure the buttons were unique when clicked, you'll want a way of tracking which have been seen. I'm using a JS Object like a Set here for compat with older browsers.
var clickCount = 0;//count the clicks
var clickTracker = {};//track which id's were clicked
var clickThreshold = 2;//the number of clicks we want before executing the if block
function clickHandler(){//callback function for the event
if(clickTracker[this.id] === undefined){//we haven't seen this id yet
clickCount++;//increment the number of buttons clicked
clickTracker[this.id] = 1;//flag for tracking the click
if(clickCount >= clickThreshold){//we saw at least clickThreshold clicks
console.log(clickCount + 'unique clicks happened!');
//your work here
}
}
}
$('.cls').click(clickHandler);//bind events
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id='btn1' class='cls'>1</button>
<button id='btn2' class='cls'>2</button>
<button id='btn3' class='cls'>3</button>
<button id='btn4' class='cls'>4</button>
<button id='btn5' class='cls'>5</button>
You can use event delegation to track clicks on .menulink elements. using e.delegateTarget we can have the parent container hold a variable that determines if a .menulink element has been clicked previously, and if it has, we can have it change the background.
To do this I switched the click method to an on method. The on methods parameters are:
$(element).on(event, delegated selector, function)
JQuery .on documentation
Delegation simply means that instead of checking if each button has been clicked by placing an event on the button, we place an event on the container of the buttons and ask if the element that caused the event matches our delegated selector. If it does the provided function is fired. To access the parent of the delegated element within the code we can use the passed back event object, or in this case e.delegateTarget
JQuery delegateTarget documentation
Since everything in JavaScript is an Object, we can assign new properties and methods to anything that is not explicitly part of the Browser's most base architecture. This absolutely includes the body of a page.
In the code below, I place a new property clicked on the body of the page. This is added on click of the first .menulink element, and is checked upon each subsequent click.
Because of this we can know if it is a second click by determining if body.clicked is true. If it is we tell the script to change the background image.
$(function() {
$('body').on("click", ".menulink", function(e){
if(e.delegateTarget.clicked) $("#bg").attr('src',"http://placehold.it/333/3ef/img/picture1.jpg");
else e.delegateTarget.clicked = true;
e.preventDefault();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
switch me
switch me
<img src="http://placehold.it/333/fe3/img/picture2.jpg" id="bg" />
This is what I was looking for
<script>
$(document).ready(function() {
var chosenColors = [];
$(".colors button").click(function() {
chosenColors.push($(this).text())
check();
});
function check() {
if (chosenColors.length === 2) {
$(".pretty-picture").attr("src", chosenColors.sort().join("-") + ".png")
chosenColors = [];
}
}
});
</script>
<body>
<div class=colors>
<button type="button">red</button>
<button type="button">yellow</button>
<button type="button">blue</button>
</div>
<img class="pretty-picture">
</body>

Masonry - deleting elements by clicking on something else, than the element itself

In Masonry, it is possible to delete an element by clicking on it. The catch is, that You have to click directly on that element - so if you use these "bricks" as an image gallery (as long as these photos are included as a background image) You can delete them, by clicking on the element. The problem is, when you use these as some messages/info/other content containers. Then, due to formatting-related stuff the parent element gets "hidden" behind other tags, and You can't actually click on it.
The problem is shown here:
http://jsfiddle.net/dan1410/SfU5T/
You can close red boxes, but not green ones, as they are overlapped by another elements.
I've tried code like:
eventie.bind( container, 'click', function( event ) {
// don't proceed if item was not clicked on
if ( !classie.has( event.target, 'closeable' ) ) {
return;
}
// remove clicked element
msnry.remove( event.target );
// layout remaining item elements
msnry.layout();
});
});
and
var todelete = document.querySelector('.closeable');
eventie.bind( container, 'click', function( event ) {
// remove clicked element
msnry.remove( todelete );
// layout remaining item elements
msnry.layout();
});
});
but You still have to click directly on the element You'd like to close...
My masonry content structure looks like
<div id="masonry" >
<div class="item blue closeable">
<div id="itheader"><h2 class="secsectiontitle">Space available</h2></div>
<div id="itcontent">
some statistics here...<br/>
and here, too
</div>
</div>
Only elements with .closeable class are supposed to be closeable.
So, the question is: how to close an element using a button/a link?
I'm not very familiar with JS, so I'd like to ask You guys for help. Thank You in advance!
Unless there are handlers that stops the propagation of the click event on children elements, the click event should bubble up without any issues.
Also, if you are using jQuery, you should use the jQuery Masonry's API.
Note: I couldn't access your fiddle and couldn't test the solution
var $container = $('#masonry').on('click', '.closeable', function (e) {
$container.masonry('remove', e.currentTarget);
$container.masonry(); //layout
$container.masonry('reloadItems'); //OP said it was also required
});

Div slide up when click in items inside it

I have a div that slides down (opens) when I click a certain input select. Inside this div, I have some other input selects and my objective is to slide up the div when I click on the rest of the page.
My problem:
The div slides up when I select some item in the input selects inside it, and I don't want this to happen.
Is there some way to slide up the div only when I click outside it?
Why are the selects inside the div making it to slide up as well?
This is my javascript to slide up the div:
$(document).mouseup(function (e) {
var container = $('.myDiv');
if (container.has(e.target).length === 0) {
$(container).removeClass('close');
$(container).addClass('open');
$(container).next().slideUp(200);
}
});
The div slides up when I select some item in the input selects inside
it, and I don't want this to happen.
Is there some way to slide up the div only when I click outside it?
Why are the selects inside the div making it to slide up as well?
Use event.stopPropagation() on the child element(s) to prevent the slide event being triggered by them.
event.stopPropagation - Prevents the event from bubbling up the DOM
tree, preventing any parent handlers from being notified of the event.
Here's a simple jsFiddle and the basic example below.
jQuery:
$('div').click(function(){
$('#slideMeUp').slideUp();
});
$('select').click(function(e){
e.stopPropagation();
});
HTML:
<div>Clicking here will trigger it!
<select>
<option>This won't trigger the click event anymore!</option>
</select>
Clicking here will also trigger it!
</div>
<div id="slideMeUp">Only clicking the outer div will slide me up!</div>
you can check you e.target.id with your container id
$(document).mouseup(function (e) {
var container = $('.myDiv');
if(e.target.id==$(this).attr('id'))
{
if (container.has(e.target).length === 0) {
$(container).removeClass('close');
$(container).addClass('open');
$(container).next().slideUp(200);
}
}
});
If it's specific items that are causing problems, perhaps something like this?
On click tell it to to slideUp your div as long as the clicked item is "not" in the list.
('body').click(function(event) {
if (!$(event.target).is('#id_of_item .class_to_ignore')) {
var container = $('.myDiv');
$(container).removeClass('close');
$(container).addClass('open');
$(container).next().slideUp(200);
}
});
I'd suggest binding mousedown rather than mouseup. There are inconsistencies in behaviour between browsers, this may have something to do with your issue.
You should also add some logic to check the clicked element isn't the div itself, clicking just outside of an input, but still inside of the div would currently cause the slideUp to occur.
if (!container.has(e.target).length && !container.is(e.target)) {
...
}
Other than that, it should work fine.
Have a fiddle

how to make the menu close if it is clicked out

i have an menu with some values and i got someting hidden and while click on more button it shows like google more menu... if it is clicked out it is not hiding till the more menu is clicked once again
More<small>▼</small><div class="more list" id="one" style="display:none">test <span style="color:#329">|</span> test1 <span style="color:#169">|</span> test4</div></div>
Script:
function toggle(one)
{
var o=document.getElementById(one);
o.style.display=(o.style.display=='none')?'block':'none';
}
how to make it close while the mosuse clicks on any other place other than the menus
Try using the onblur event.
I see you've tagged this with jQuery, if that is an option, you can clear up the link a bit, like this:
More<small>▼</small>
And use unobtrusive script combined with event bubbling to your advantage, like this:
$(function() {
$(".more_link").click(function(e) {
$(this).next(".more").toggle();
e.stopPropagation();
});​​
$(".more").click(function(e) {
e.stopPropagation();
});
$(document).click(function() {
$(".more").hide();
});​
});
You can test it out here, this only closes the menu if you clicked neither the menu of the toggle, e.g. clicking one of the test links will not close it. If you want it to, just remove the $(".more").click(function(e) { e.stopPropagation(); }); portion.
It uses event.stopPropagation() to stop the click from bubbling up to document, which if happens (and would if you clicked anything else) triggers its click handler, closing all the .more elements.
I wouldn't use onBlur because it's not a good accessibility approach (for example if the user is using tab to navigate the page).
Look at this solution instead:
jQuery click event for document but ignore a div
Typically, I let the event bubble up to the 'body' or 'html' doc and check if the target is what i want (and/or isn't contained within what i want). If the event target is not contained within your menu, then perform your desired operation (in this case, hide the div).
i.e.
jQuery(document).ready(function(){
jQuery("html").bind("click", function(evt){
var $target = jQuery(evt.target);
var shouldShowMenu = $target.hasClass("menu_toggle");
shouldShowMenu |= $target.parents(".menu_toggle, .more_list").length;
if(!shouldShowMenu)jQuery(".more_list").hide();
});
});
NOTE: your markup would needs to be extended such that the "more" href becomes has a class attribute, class="menu_toggle"

How to stop propagation of a bound function not the entire event?

I have a click function bound to many elements. It is possible that sometimes these elements may sit within one another. So, the click event is bound to a child and also bound to its parent. The method is specific to the element clicked. Naturally, because of event bubbling, the child's event is fired first, and then the parents. I cannot have them both called at the same time because the parents event overwrites the event of the child. So I could use event.stopPropagation() so only the first element clicked receives the event. The problem is that there are other click events also attached to the element, for example, I am using jQuery's draggable on these elements. If I stop the propagation of the click event, then draggable doesn't work, and the following click events are not called.
So my question is: Is there a way to stop the event bubbling of the method the event will call and not the entire event?
Brilliant John, but here is the problem:
<div id="Elm1"><!-- relative -->
<div class="Elmchildren"></div><!-- absolute-->
<div class="Elmchildren"></div><!-- absolute-->
<div class="Elmchildren"></div><!-- absolute-->
<div id="Elm2"><!-- relative -->
<div class="Elmchildren"></div><!-- absolute-->
<div class="Elmchildren"></div><!-- absolute-->
<div class="Elmchildren"></div><!-- absolute-->
</div>
</div>
Click event is bound to #Elm1 and #Elm2. The .Elmchildren are width and height 100%. So they are actually the current targets.
try someting like this
$(mySelector).click(function(evt) {
if (evt.target == evt.currentTarget) {
///run your code. The if statment will only run this click event on the target element
///all other click events will still run.
}
});
The suggested solution
evt.target == evt.currentTarget
is nice, but there are cases where it does not help.
Example: A (suckerfish-style) menu structure with nested ul/li lists.
The mousemove event comes from a link inside a list item, which is a child of an ul-list, which is again a child of another list item. Typical for a html menu structure with submenus.
The evt.target would be the link tag, but we are interested in the mousemove on the list item.
Even worse: The link tag could contain span or img tags or other nested stuff. Then evt.target would be this span or img.
What seems to work here is to catch the event on a parent / root item, and then check the parents of evt.target.
Like this (with jQuery),
var $menu = $('div#menu');
$('body').mousemove(function(evt){
var element = evt.target;
// find the deepest list item that was affected by this mouseover event.
var list_item;
var in_menu = false;
while (element) {
if (element == $menu[0]) {
in_menu = true;
break;
}
else if (!list_item && element.tagName == 'LI') {
// we found a list item, but we are not sure if we are inside the menu tree.
list_item = element;
}
}
// do something with the result.
if (!in_menu) {
.. // close all submenus
}
if (list_item) {
.. // open the submenu for this list item.
}
else {
// mouse in menu, but not hovering an item.
// leave the submenus open. (?)
}
});
Maybe some of this could be abbreviated with jQuery like $(evt.target).parents().is($menu), but I did not get this to work. Also, I would guess that this explicit loop with element.tagName is faster.

Categories