Only execute event on outer html element - javascript

All the answers I could find in relation to this question are trying to do things the opposite direction. So… is this even possible?
I have a simple snippet of HTML
<div class="launcher" data-info="something">
Text, or image, or whatever
</div>
The launcher class attaches an event to the div, which takes the data-info value and does something with it (e.g. launches a video in an overlay).
How do I get only the div's event to fire? (The inner link is there for no-script and semantic reasons; the full code includes various schema.org properties.)
Embedded script - onClick="return false;" - is not an option; behavioural coupling is evil. I have no problem attaching another event to the <a>, because that is a class definition. Yes, I need it to work pre IE9 (because there are people out there who…) A pure javascript (not jQuery) response would be appreciated.

You can check the event.target as follows:
var parent = document.getElementsByClassName("launcher")[0];
parent.addEventListener("click",function(e){
if(e.target.className.indexOf("launcher")> -1){
alert("click!");
}
});
div{
height:50px;
background:dodgerblue;
}
<div class="launcher" data-info="something">
Text, or image, or whatever
</div>
Or you can add another click event listener for the anchor and prevent it's propagation as follows:
var parent = document.getElementsByClassName("launcher")[0];
parent.addEventListener("click",function(e){
if(e.target.className.indexOf("launcher")> -1){
alert("click!");
}
});
var anchor = document.querySelector(".launcher a");
anchor.addEventListener("click",function(e){
e.stopPropagation();
})
div{
height:50px;
background:dodgerblue;
}
<div class="launcher" data-info="something">
Text, or image, or whatever
</div>

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>

Disable contextmenu for a specific container and its children

I need to disable contextmenu only inside a specific div #wrapperand its children, and not the whole page. This is what I'm doing:
document.addEventListener('contextmenu', function (event) {
console.log(event.target.id);
if (event.target.id === 'wrapper') {
event.preventDefault();
}
});
.. but it doesn't seem to work.
You're approaching this the wrong way: you're adding the listener to the document, which may be ok, but it's easier to add it to the element itself, and you are checking event.target.id, which is the ID of the current clicked element (e.g. a children of your wrapper), not the wrapper.
To make this work you can easily do something like this instead:
var myWrapper = document.getElementById('wrapper');
myWrapper.addEventListener('contextmenu', function(e) {
e.preventDefault();
}, true);
This is a solution that work fine
<div id="wrapper" oncontextmenu="return false">
#wrapper
<div class="childds">
</div>
The code you have in your question works perfectly. One possibility of why the context menu still showed up is that you in fact clicked on a child of #wrapper, instead of clicking on the element itself:
HTML
<div id="wrapper">
#wrapper
<div class="inner">
#wrapper .inner
</div>
</div>
Working example demonstrating this issue on JSFiddle.
You can overcome this by attaching the event handler to the desired element directly instead. This way, right-click events on child-elements will bubble up to #wrapper, and thus fire the event as expected:
JavaScript
document.getElementById('wrapper').addEventListener('contextmenu', function (event) {
event.preventDefault();
});
Working example on JSfiddle.

jQuery won't bind click to underscore template using .on() for items added via function

I'm using underscore to create some elements and appending them to a div with jQuery.
At the bottom of the page I'm using jQuery's .on() to respond to clicks on the elements.
$('.pickup').on('click',
function(e) {
alert("hello");
}
);
Via some user interaction (in Google maps), I've got to add more elements to the div and want them to respond to clicks as well. For some reason they do not. I've pared it all down on jsfiddle:
http://jsfiddle.net/thunderrabbit/3GvPX/
When the page loads, note that clicking on the lines in output will alert('hello') via jQuery.
But click the [add] button and the new lines do not respond to clicks.
My HTML
<div id="unit_2225" class="pickup">
<span>Click me; I was here first</span>
</div>
<script type="text/template" id="unit-template">
<div class="unit-item">
<span class="pickup">
<span>click us (<%= unit_id %>) via underscore</span>
</span>
</div>
</script>
<div id="divID">
</div>
<button>add</button>
My Javascript
var addUnitToDiv = function(key,val) {
console.log(val);
var template = _.template($('#unit-template').html(),val);
$('#divID').append(template);
}
var unit_ids = [{unit_id:'hello'},
{unit_id:'click'},
{unit_id:'us'},
{unit_id:'too'},
{unit_id:112}];
$.each(unit_ids, addUnitToDiv);
var unit_pids = [{unit_id:'we'},
{unit_id:'wont'},
{unit_id:'respond'},
{unit_id:'to'},
{unit_id:'clicks'},
{unit_id:358}];
createMore = function() {
$.each(unit_pids, addUnitToDiv);
}
$('.pickup').on('click','span',function() {
alert("hello");
});
$('button').click(createMore);
I found a similarly worded question but couldn't figure out how to apply its answer here.
Instead of binding events directly to the elements, bind one event to their container element, and delegate it:
$("#divID").on("click", ".pickup", function () {
// Your event handler code
});
DEMO: http://jsfiddle.net/3GvPX/3/
In this case, the event handler is only executed for elements inside of the container #divID that have the class "pickup".
And in your scenario, the elements are being added to the element with an id of "divID". Thus, where the two selectors came from.
This is handy because, as you've found out, dynamically adding elements doesn't magically bind event handlers; event handlers bound normally with .on() are only executed (bound) on those present at the time of binding.
It could even help if you change the delegated selector to "span.pickup" (if you know the elements will always be a <span> like in your template), so that the DOM is filtered by the tag name first.
Reference:
http://api.jquery.com/on/#direct-and-delegated-events
Working demo http://jsfiddle.net/u2KjJ/
http://api.jquery.com/on/
The .on() method attaches event handlers to the currently selected set of elements in the jQuery object. You can attach the handler on the document level.
Hope it fits the need, :)
code try the code changed below
$(document).on('click','.pickup',function() {
alert("hello");
});

Preventing event bubbling (for javascript onclick events)

I am using javascript to interact with a CMS which provides a button for users to add things to their basket.
However, I am using the javascript to try and prevent the customer from doing so unless they have made a selection from a drop-down menu elsewhere on the page.
As there are many different buttons that could potentially get them to the basket (including the example below) and all of which have different methods for doing so, rather than write many lines of code to prevent each method and then re-enable that method when a selection is made I am trying to do a kind of 'catch-all' fix where I just cover any such buttons / links with another div so as to effectively 'mask' the button below it until they make a decision.
I first tried to use absolute positioned divs to do this which works beautifully until the user does something like re-size a textbox on the page and then suddenly my absolutely positioned div is in the wrong place!!
So I'm now using JQuery's .wrap() which solves this problem nicely.. BUT.. Now I can't use z-index to position the div above the required buttons as those buttons are within the mask not below it!
I have done a lot of reading about event bubbling but I am not sure whether I've not found the right information yet, or maybe I understand it correctly or possibly that event bubbling is leading me down the wrong path all together as I can't seem to take those concepts and apply them to this scenario.
so.....
given the following HTML structure:
<div class="btnMask">
<div class="button">
<a onclick="pageSubmit();return false;" href="#" id="addToBasket">
<span>Add to Basket</span>
</a>
</div>
</div>
where the div with class="btnMask" is added by my javascript.
Plus the following JQuery:
$('.btnMask').click(function() {
// prevent default actions and alert the customer to select something;
});
How do I go about stopping the tag firing when clicking the .btnMask div?
and (in case the answer to that does not make the answer to my other question obvious...)
How would I switch that on and off ? (I have a function that checks the drop-down onchange and sets the z-index to 99 / -99 so I would want to change this to incorporate this new method.)
Thank you in advance for your help.
<< EDIT >>
Using the initial answers to this I managed to solve the problems for links that take you away from the page using a regular href.
So I have now fixed the links where the HTML is like the following:
<div class="btnMask">
<div class="button">
<a id="nextPage" href="/link/toanotherpage.asp?id=667868465726122926234">
<span>Click to go to Page 2</span>
</a>
</div>
</div>
However, like I said there are many methods being used to take people away from the page and and e.preventDefault(); and e.stopPropagation(); don't work for my original example (presumably because they use an onclick rather than a href ?).
Is there a way to do the same thing as e.preventDefault(); and e.stopPropagation(); are doing on my .btnMask div but will also deal with contained links that are being trigged by an onclick?
thanks
<< EDIT >>
Updated the question title to reflect the exact issue rather than just event bubbling on regular links.
If you want to prevent event bubbling and cancel default action then you can return false from the event handler.
$('.btnMask').click(function() {
return false;
});
Or use preventDefault and stopPropagation
$('.btnMask').click(function(e) {
e.preventDefault();
e.stopPropagation();
});
$('.btnMask').click(function(e) {
e.stopPropagation();
});
Your onclick handler is fired before your jquery click handler. You can do something like this
function pageSubmit() {
alert('pageSubmit');
}
var link = document.getElementById('addToBasket');
var linkClickHandler = link.onclick;
link.onclick = null;
$('.button').data('linkClickHandler', linkClickHandler);
$('.button').on('click', function(e){
var clickHandler = $(this).data('linkClickHandler');
var link = $(this).find('a').get(0);
clickHandler.apply(link, [e]);
});
$('.btnMask').on('click', function(e){
if (!$(this).hasClass('test')) {
e.preventDefault();
e.stopPropagation();
}
});
and the html as
<div class="button">
<a onclick="pageSubmit();return false;" href="#" id="addToBasket">
<div class="btnMask test">
<span>Add to Basket</span>
</div>
</a>
</div>
If you remove the class test from btnMask div the pageSubmit handler will not be called,
and when it is present the handler is called.

How to use javascript onclick on a DIV tag to toggle visibility of a section that contains clickable links?

Hi I've got a DIV section that has only its title visible initially. What I would like to achieve is that when the visitor clicks anywhere on the area of toggle_section the toggle_stuff div toggles between visible/hidden.
<div id="toggle_section"
onclick="javascript: new Effect.toggle('toggle_stuff', 'slide');">
<div id="toggle_title">Some title</div>
<div id="toggle_stuff">
some content stuff
Some link
</div>
</div>
However, the way it is set-up right now, if I have any <a> link within the toggle_section, clicking that link will also execute the onclick event.
Then my question is what would be the best way to set this type of behavior?
The most simple solution is to add an extra onclick handler to the link within your DIV which stops event propagation:
<div id="toggle_section"
onclick="javascript: new Effect.toggle('toggle_stuff', 'slide');">
<div id="toggle_title">Some title</div>
<div id="toggle_stuff">
some content stuff
<a href="/foo.php"
onclick="Event.stop(event);"
>Some link</a>
</div>
</div>
The above example uses Prototype's Event.stop() function in order to facilitate a cross browser event propagation stop.
As you use the inline onclick() handler, most (if not all) browser will traverse the event in the bubbling phase first (which is what you want).
A good guide to understanding the actual reasons behind this behaviour and the differences between event capturing and event bubbling can be found at the excellent Quirksmode.
in script :
function overlayvis(blck) {
el = document.getElementById(blck.id);
el.style.visibility = (el.style.visibility == 'visible') ? 'hidden' : 'visible';
}
activator link, followed by content (no reason that couldn't be else on the page):
<div onclick='overlayvis(showhideme)">show/hide stuff</div>
<div id="showhideme">
... content to hide / unhide ...
</div>
I got this from Modal window javascript css overlay - had to search for the source and was pleased to find it was this site. :)
After I posted my first question I could not wait to try to think about it once more and it seems that I have found a quite simple way to achieve this.
I have moved the onlick Effect.toggle into a separate function like:
function someClick(event) {
if (event.target.nodeName == 'A') {
return;
} else {
new Effect.toggle('toggle_stuff', 'slide');
}
}
I suppose this would only work for A tags and not anything else that is clickable though.
I don't really know if this would work, but try giving the link element a bigger z-index value than the toggle_section div.
something like :
#toggle_section a { z-index: 10; }
Add an onclick handler to stop event propagation.
With JQuery use:
onclick="event.stopPropagation()"
With Prototype use:
onclick="Event.stop(event)"

Categories