Undefined href for some clickable elements - javascript

I'm trying to get link (url of clickable elements) with the left mouse click, next method doesn't work for all elements:
function callback(e) {
if (e.button != 0 ) {
return;
}
alert(e.target.href);
}
document.addEventListener('click', callback, true);
For example for some elements on Youtube site - titles or thumbnails (all of them are clickable and they lead to some video/playlist):
href is undefined
but it's clickable and Google Chrome browser shows a preview of link to which this element leads:
UPDATE
The problem that some A tags on Youtube site wraps other elements inside them: <span>...<span/><div.......>
I tried debug mode (inspect), selected some of such element to inspect and it picked <span> inside of <a>.
Additional Solution: https://jsfiddle.net/z2huqjjh/2/ (will be good solution if links (A tags) are dynamically being added to a page)

By default, events bubble. This means that you could have an element that is nested within 100 others. Clicking on that nested element will cause a click event and that event will propagate up through all the ancestor elements until it is either cancelled or reaches the window.
Now, just about everything in the document is clickable. Just because something is clickable doesn't mean it will navigate to a URL, like an <a> element does.
For example:
document.querySelector("div").addEventListener("click", function(){
alert("Thanks for clicking me!");
});
<div>I'm a <div> and I don't have an 'href'. But, click me anyway</div>
Since only a few elements actually have an href attribute, you could alter your code to look only at those:
function callback(e) {
if (e.button != 0 ) {
return;
}
alert(e.currentTarget.href);
}
// Get all the anchors and place into an array
var anchorArray = Array.from(document.querySelectorAll("a"));
// Loop through the anchors
anchorArray.forEach(function(anchor){
// Assign a click event handler to each. When the click event
// bubbles to the element, the callback will be called
anchor.addEventListener('click', callback);
});
<div>I'm a div - click me anyway</div>
<span>I'm a span inside of an anchor, click me too!</span>

Related

Which Click event handler is to use when changing the content dynamically in jQuery?

I have a small application in jQuery, which takes the href value of an anchor element and inserts that as a div's Id. The div is a basic popup window which is only visible if it's triggered.
The popup window on gets triggered if a anchor tag gets clicked with the same href value as the id of the popup div.
HTML Code:
Item 1
Item 2
Item 3
<div class="popup"></div>
jQuery Code:
var items = ["#item1", "#item2", "#item3"];
$.each(items, function()
{
$(document).on("click", this, function(e)
{
e.preventDefault();
var href = $(this).attr("href");
var length = href.length;
var anchor = href.substring(1, length);
var popup = $(".popup").attr("id", anchor);
});
});
Problem:
The popup window should be triggered once the client clicks on any of the anchors above. However it only gets triggered, on the second click. I guess the first one sets the Id and the second opens is, with the set value.
I have also tried to use another type of click event and it worked for the first click. The event, which have been working was:
$(this).on("click", function(e)
{
// Stuff goes here as above
});
My problem is that I cannot use this type of event handler, because I will be changing the content of the anchor href's dynamically with jQuery.
Question:
How is it possilbe to make the original code working as I expect, so the client should only click once to the anchor tag to get the popup window? Anything else I should consider as well?
$('#item1').on("click", function(e)
{
// Stuff goes here as above
});
$('#item2').on("click", function(e)
{
// Stuff goes here as above
});

jQuery .on('click') firing multiple times when used with :not() selector

Good morning,
I have a set of boxes on a page that are presented as a list, and within these boxes there might be some links that can be clicked. I want the links within the boxes to work as normal (i.e. bubble up and either perform the default action or then be handled by event handlers further up the DOM), but if the box is clicked anywhere else then it should be caught by a particular event handler attached to the "list" containing all the boxes.
Simple html representation
<div class="boxlist">
<div class="box" data-boxid="1">
Some text, and possibly a link and another link, and perhaps even a third link.
</div>
<div class="box" data-boxid="2">
Some more text, this time without a link.
</div>
</div>
The javascript that I thought should work.
$(function () {
$('.boxlist').on('click', '.box :not(a)', function (e) {
var boxid= $(this).closest('.box').data('boxid');
console.log('open: ' + boxid);
});
});
My expectation was that the above javascript should handle all clicks that did not originate from tags. However, for some reason when the box is clicked (either the box itself, or an tag, doesn't matter), it fires this event X times, where X is the total number of tags within the list of boxes.
So I have two questions:
1. What am I doing wrong with the :not() selector.
2. Is there a better way to handle this scenario?
Thank you for helping!
linkUsing jQuery :not selector actually is very slow ex:http://jsperf.com/not-vs-notdasdsad/4 and it's way better to just use event delegation. So in this case you want to keep track of every click on the .boxlist but check the node type to see if its an anchor or not. This is an example.
$(function () {
$('.boxlist').on('click', function(ev){
if(ev.target.tagName != "A"){
// handle box click code
console.log('box click');
return false;
}
// Otherwise allow event to bubble through.
});
});
and here is a jsfiddle example
http://jsfiddle.net/drXmA/
Also their are a few reasons your code doesn't work
.box :not(a)
should be
.box:not(a)
and the reason this also does not work is because .box is not an anchor tag it has children elements that are anchor tags it will never find an anchor tag named .box if their is one the callback would not execute. Changing the .box to an anchor tag will make it so the code doesn't execute because .box is an anchor and it is only running when .box:not(a)
I guess you want something like this:
$('.boxlist').on('click', '.box:not(a)', function (e) {
var boxid = $(this).closest('.box').data('boxid');
console.log('open: ' + boxid);
}).on('click', '.box a', function (e) {
e.preventDefault().stopPropagation();
});
DEMO FIDDLE
I think better to stop the default behavior and stop the event bubbling to its parent. .on() chain to the .box items excluding <a> from it and stop the default behavior and event bubble with e.preventDefault().stopPropagation();

jQuery click anywhere in the page except on 1 div

How can I trigger a function when I click anywhere on my page except on one div (id=menu_content) ?
You can apply click on body of document and cancel click processing if the click event is generated by div with id menu_content, This will bind event to single element and saving binding of click with every element except menu_content
$('body').click(function(evt){
if(evt.target.id == "menu_content")
return;
//For descendants of menu_content being clicked, remove this check if you do not want to put constraint on descendants.
if($(evt.target).closest('#menu_content').length)
return;
//Do processing of click event here for every element except with id menu_content
});
See the documentation for jQuery Event Target. Using the target property of the event object, you can detect where the click originated within the #menu_content element and, if so, terminate the click handler early. You will have to use .closest() to handle cases where the click originated in a descendant of #menu_content.
$(document).click(function(e){
// Check if click was triggered on or within #menu_content
if( $(e.target).closest("#menu_content").length > 0 ) {
return false;
}
// Otherwise
// trigger your click function
});
try this
$('html').click(function() {
//your stuf
});
$('#menucontainer').click(function(event){
event.stopPropagation();
});
you can also use the outside events
I know that this question has been answered, And all the answers are nice.
But I wanted to add my two cents to this question for people who have similar (but not exactly the same) problem.
In a more general way, we can do something like this:
$('body').click(function(evt){
if(!$(evt.target).is('#menu_content')) {
//event handling code
}
});
This way we can handle not only events fired by anything except element with id menu_content but also events that are fired by anything except any element that we can select using CSS selectors.
For instance in the following code snippet I am getting events fired by any element except all <li> elements which are descendants of div element with id myNavbar.
$('body').click(function(evt){
if(!$(evt.target).is('div#myNavbar li')) {
//event handling code
}
});
here is what i did. wanted to make sure i could click any of the children in my datepicker without closing it.
$('html').click(function(e){
if (e.target.id == 'menu_content' || $(e.target).parents('#menu_content').length > 0) {
// clicked menu content or children
} else {
// didnt click menu content
}
});
my actual code:
$('html').click(function(e){
if (e.target.id != 'datepicker'
&& $(e.target).parents('#datepicker').length == 0
&& !$(e.target).hasClass('datepicker')
) {
$('#datepicker').remove();
}
});
You could try this:
$(":not(#menu_content)").on("click", function(e) {
e.stopPropagation();
// Run your function when clicked anywhere except #menu_content
// Use with caution, 'cause it will prevent clicking on other elements
});
$("#menu_content").on("click", function(e) {
e.stopPropagation();
// Run when clicked on #menu_content
});

Disable slideDown/Up on links inside div

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.

How to attach a onclick callback to a div but not on a link inside the div?

Html
<div class='item_container'>
[...bunch of links and pictures...]
<a class='item_owner'>John Doe</a>
</div>
Javascript
/**
Bind the onclick only if you hover on the item since we got a lot
of items and several events and plugins to setup on them.
*/
$('.item_container').live('mouseenter', function(e){
$this = $(this);
if (!$this.data('isSetup')) {
$this.click(function(e){
// do magic
return false;
});
[... a lot of other stuff]
$this.data({'isSetup': true});
}
});
Of course when I click anywhere in the div, it performs 'do magic'. Thanks to return false, if I click on any link in the div, it still performs 'do magic' and doesn't change the page, which is the expected behavior.
But there is one link that is suppose to actually change the page, the owner link. Trouble is, with my current set up, I prevent it from working.
You need to stop the propagation of the event from the links to the parent .item_container.
Add this block to the code:
$('.item_container a.item_owner').live('click', function(e){
e.stopPropagation();
});

Categories

Resources