click works with jQuery but not vanilla js - javascript

If I use jQuery and click on the icon it works fine:
$(document).on('click', '.fileuploader-action-sort', function() {
alert('clicked');
});
But if I use vanilla js, I have to literally click at the very bottom of the icon, like on the tip for it to actually work otherwise nothing happens when clicking anywhere else on the actual icon.
document.body.addEventListener("click", e => {
if (!e.target.matches(".fileuploader-action-sort")) return;
alert('clicked');
});
Here is the html:
<a class="fileuploader-action fileuploader-action-sort" title="Sort"><i></i></a>
I am generating the icons based on the number of database records I have which is why I didn't use document.querySelector('.fileuploader-action-sort');

Because e.target refers to the whole document in your vanilla js example if you click on the div, and it refers to the i tag if you click on any content inside of it. But in the jQuery example it refers to the .fileuploader-action-sort class.
One way to notice it is to console.log(e.target) :
document.body.addEventListener("click", e => {
console.log(e.target)
if (!e.target.matches(".fileuploader-action-sort")) return;
alert('clicked');
});
<a class="fileuploader-action fileuploader-action-sort" title="Sort"><i>Test</i></a>
So you need to listen to the i tag and not the class in itself :
document.body.addEventListener("click", e => {
if (!e.target.matches(".fileuploader-action-sort i")) return;
alert('clicked');
});
<a class="fileuploader-action fileuploader-action-sort" title="Sort"><i>Test</i></a>

Related

Triggering a link if wrapped in an <em> tag

I am having an issue where a modal isn't triggering if it is wrapped in an tag.
In my example, if you click in the "normal" font-style part of the link, it fires properly, if you click where the italics are, it won't.
Any ideas?
JS
$(function () {
const openModals = [];
$('.modal-button').click(e => {
e.preventDefault();
$(e.target).closest('.modal').add('body').addClass('open');
openModals.push($($(e.target).attr('href')).show());
});
$(window).add('.close').click(e => {
e.stopPropagation();
if ($(e.target).is('.modal, .close')) {
const closing = openModals.pop().addClass('modal-content-active');
setTimeout(() => {closing.hide().removeClass('modal-content-active')}, 0);
if (openModals.length > 0) {
openModals[openModals.length - 1].removeClass('open');
} else $('body').removeClass('open');
}
});
});
FIDDLE
in the first event handler, you are referencing the "target" and not the "currentTarget"
e.target represents the exact element being clicked - in your case the <em/> - while e.currentTarget represents the element the event handler is attached to, which is where your href value is.
I'd change the two references to e.target in the first event handler to e.currentTarget and things should work as expected.
$('.modal-button').click(e => {
e.preventDefault();
$(e.currentTarget).closest('.modal').add('body').addClass('open');
openModals.push($($(e.currentTarget).attr('href')).show());
});
https://jsfiddle.net/q7o6f9su/
https://jsfiddle.net/qLpcfx8k/
You just need to pass the same href to the tag and be happy :)
This is the trigger <em href="#myModal1"> for the first modal</em><br>
This is the trigger <em href="#myModal1"> for the second modal</em>

How to Stop Unwanted repeated variable in twitter-bootstrap dialog?

I have multi link to delete via ajax:
<a id="id-1">link1</a>
<a id="id-2">link2</a>
<a id="id-3">link2</a>
<a id="id-4">link2</a>
...
this is a simplified of my code:
$(document).on("click", "[id^=id-]",function(event) {
event.preventDefault();
var btnid = this.id;
alert('1:'+btnid );
// a dialog confirm to aks delete in bootstrap
$("#confirmbtn").on( "click", function(event) {
alert('2:'+btnid );
});
})
when I refresh page for first one I got this in alert:
(click on <a id="id-1">link1</a>)
1:id-1
2:id-2
but for second,third and ... I got wrong!
for example for second:
(click on <a id="id-1">link2</a>)
1:id-2
2:id-1
2:id-2
the third:
(click on <a id="id-1">link3</a>)
1:id-3
2:id-1
2:id-2
2:id-3
I expect
1:id-3
2:id-3
can help me to solve that?
As you are binding event handler inside another event handler, a new event handler is getting attached every the element is clicked, thus you are getting the issue. You can use .data() to persist arbitrary data.
$(document).on("click", "[id^=id-]",function(event) {
event.preventDefault();
var btnid = this.id;
alert('1:'+btnid );
$("#confirmbtn").data('id', this.id)
})
// a dialog confirm to aks delete in bootstrap
$(document).on( "click", "#confirmbtn", function(event) {
alert('2:'+$(this).data('id'));
});
You are binding multiple eventhandlers to the button. With each clicked link (link-1, link-2 etc.) you add a new one to the button, but the existing ones remain. To solve this, you could add an event handler to the confirm-button on initialization and use a variable, which tells you anytime, which link was clicked last. You could do this like this:
$(document).ready(function() {
var lastLinkId;
$("#confirmbtn").click(function() {
alert("2: "+lastLinkId);
});
$(document).on("click", "[id^=id-]",function(event) {
event.preventDefault();
lastLinkId = this.id;
alert('1: '+lastLinkId);
});
});

JQuery selector to exclude child elements

I'm using this click method to reveal additional classes inside a .tile
var $tiles = $('.tile');
$tiles.on('click', function(){
var $this = $(this);
$this.toggleClass('large'); // change layout of tile
$this.children('.details').toggle(); // display additional info
})
Since a .tile may contain links, I'd like to limit the click functionality. I don't want the function to trigger when a link inside .tile is clicked.
Edit: While #antyrant's answer is working for normal links, I noticed in my example the problem persists with on of the links that uses fancyBox.
This is what my HTML looks like:
<div class="tile">
<ul class="details">
<li><a class="download"> href="#">Download</a></li>
<li><a class="fancybox-media" href="#">Video</a></li>
</ul>
</div>
Clicking the download link works fine, but the fancyBox will not work!
Edit 2: See this jsFiddle for a working example.
You need to stop events propagation on child elements, for example:
$tiles.find( 'a' ).click( function( e ) {
e.stopPropagation();
});
UPDATE:
If this can be done as you use some plugins for example you can check if event target has your base class: for example:
$('.tile').on('click', function ( e ) {
if( !$( e.target ).hasClass( 'tile' ) ) {
return true;
}
//...
see jsFiddle demo.
stopPropagation() will stop your child event from bubbling up, and being caught by the listener on the parent element.
var $tiles = $('.tile');
$tiles.on('click', function () {
console.log('clicked');
})
$('a', $tiles).on('click', function (e) {
e.stopPropagation(); //Prevents event from bubbling up
})
#antyrat is correct, stopping propagation on the anchors will achieve your goal, but that requires binding another event that isn't really necessary. Another option would be to look at the target on the event passed in to your handler.
$tiles.on( 'click', function( e ) {
if( !$( e.target ).is( 'a' ) ) { // if the element clicked is not an anchor.
// do stuff
}
});
EDIT: Here's a fiddle demonstrating this working using the updated html provided above.

Why does jQuery's one fire immediately when it's added to an element?

Here's a fiddle illustrating the problem. I am adding a jQuery one binding on the click of one element to the 'html' element. I am not expecting the 'one' event handler to fire until the next click, but it fires on the click that adds the binding. This seems to not be a problem if it is a more specific element that the 'one' event handler is added to, but it happens when I use 'html' or 'body' as the element, which is what I want to do.
This doesn't make sense to me, I'd think the first click would add the one for the next click and it wouldn't fire on the click on the link.
By the way, my actual problem could probably be solved in a better way, but I came across this and was curious why it didn't work as I expected.
Code:
html:
<div id='hello'>hello</div>
<a class="title" href="#">this example</a> is a test​
js:
$(function() {
$('a.title').click(function() {
var htmlClickBind = function (e) {
console.log('clicked on html, e.target = ' + e.target);
console.log(e.target == '');
if (!$(e.target).is('a') ) {
console.log('cleared click event');
}
else {
$('html').one('click', htmlClickBind);
}
};
$('html').one('click', htmlClickBind);
});
});​
The click event on the a.target element bubbles up to the html element, where your (just-added) handler sees it.
To prevent this, use event.stopPropgation in your a.target click handler (or return false, which does stopPropagation and preventDefault).
Updated code (see the comments): Live copy
$(function() {
// Accept the event arg ----v
$('a.title').click(function(e) {
// Stop propagation
e.stopPropagation();
var htmlClickBind = function (e) {
console.log('clicked on html, e.target = ' + e.target);
console.log(e.target == '');
if (!$(e.target).is('a') ) {
console.log('cleared click event');
}
else {
$('html').one('click', htmlClickBind);
}
};
$('html').one('click', htmlClickBind);
});
});​

jquery selector help. Everything but the specified selector

I have the following function to open an overlay menu:
$('.context-switch').click(function() {
$(".context-switch-menu").toggle();
});
To hide the menu, I would like the user to be able to click on any area outside ".context-switch-menu"
I am trying with :not() but with no success..
$('body').click(function(e) {
if ($(e.target).hasClass('context-switch')) {
return;
}
$(".context-switch-menu").hide();
});
$('.context-switch').click(function() {
$(".context-switch-menu").toggle();
return false;
});
The reason this can be difficult is because of event bubbling.
You can try something like this:
$('.context-switch').click(function(e) {
e.stopPropagation();
$(".context-switch-menu").toggle();
});
$(".context-switch-menu").click(function(e){
e.stopPropagation();
});
$("body").click(function(e){
$(".context-switch-menu").hide();
});
The e.stopPropagation() prevents the click event from bubbling to the body handlers. Without it, any click to .context-switch or .context-switch-menu would also trigger the body event handler, which you don't want, as it would nullify the effect of the .context-switch click half the time. (ie, if the state is hidden, and then you click to show, the event would bubble and trigger the body handler that would then hide the .context-switch-menu again.)
Without testing, would something like this work?:
$('.context-switch').click(function() {
$(".context-switch-menu").show();
});
$(document).click(function() {
$(".context-switch-menu").hide();
});
Instead of using document, 'html' or 'body' may work as well.
$(document).on('click', function(e) {
if (e.target.className !='context-switch-menu') {
$(".context-switch-menu").hide();
}
});
Just an idea here, based on what what others have suggested in the past:
$(document).click(function(e){
//this should give you the clicked element's id attribute
var elem = $(e.target).attr('classname');
if(elem !== 'context-switch-menu'){
$('.context-switch-menu').slideUp('slow');
//or however you want to hide it
}
});
try this, we don't want to call a function when you clicked on the element itself, and not when we click inside the element. That's why we need 2 checks.
You want to use e.target which is the element you clicked.
$("html").click(function(e){
if( !$(e.target).is(".context-switch-menu") &&
$(e.target).closest(".context-switch-menu").length == 0
)
{
alert("CLICKED OUTSIDE");
}
});
Live fiddle: http://jsfiddle.net/Xc25K/1/

Categories