what is the equivalent to the following statement in Javascript in a single line ?
$("#element1,#element2").on("click", runFunction);
For example:
var f = function() { /* Event handler */ },
els = document.querySelector(/* selector */);
for(var i=0, l=els.length; i<l; ++i)
els[i].addEventListener('click', f, false);
Just remove the line breaks and it will be in a single line.
But in ES6 you can get close:
for(var el of document.querySelector(/* selector */)) el.addEventListener('click', f, false);
Simply Do that by not keeping any space in your code
e1=document.getElementById('element1'),e2=document.getElementById('element2');if(addEventListener){e1.addEventListener('click',runFunction,false);e2.addEventListener('click',runFunction,false);}else{e1.attachEvent('click',runFunction);e2.attachEvent('click',runFunction);}
Almost certainly, what you're really looking for is called:
jQuery's Event Delegation (see jQuery's .on() documentation)
It's what everyone is looking for, even if they don't quite realize it yet ;)
Don't bind your handlers onto your elements directly -- bind your handler to a parent element (perhaps <body>) instead, and use jQuery's event delegation model to specify a selector by which bubbled sub-events are filtered. In the following case, we place a click handler on the <body> which is specified to trigger for a[href] link clicks.
// Handles all link clicks under the <body> tag (superior methodology -- much optimum)
$('body').on('click','a[href]',function(jqEvent){
var $a = $(this);
console.log("Link Clicked:",$a.attr('href'));
});
// Direct binding, which is essentially what the original asker had (inferior)
$('a[href]','body').on('click',function(jqEvent){
var $a = $(this);
console.log("Link Clicked:",$a.attr('href'));
});
Related
I'm trying to highlight any DOM element of a certain Web page when the user clicks on it. For that purpose, I iterate through all elements of the current element and disable any functionality (so e.g. I can click and not to be redirected):
var elems = window.document.getElementsByTagName('*');
for (var i = 0; i < elems.length; i++) {
elems[i].onclick = function(e){
e.preventDefault();
}
The thing is, when user clicks, a lot of click events are fired, because every element has tas behaviour, and I need to avoid unhighlight.
Any idea of how to improve that or any alternative?
Thanks a lot!
P/d: It has to be pure JS
You'll need to do two things: first of all, you want to actually add an event, not redefine its click behaviour, and secondly, uou want it to not bubble up through the dom. Try this:
var elems = window.document.getElementsByTagName('*');
for (var i = 0; i < elems.length; i++) {
// Use addEventListener to listen for events.
// Older version of IE use attachEvent, but I guess thats irrelevant.
elems[i].addEventListener("click", function(e){
e.preventDefault();
// Use stopImmediatePropagation to stop the element from passing this click to wrapping parents - because a click on a child is technically a click on the parent as well.
e.stopImmediatePropagation();
});
}
Heres more to read:
Add Event Listener: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
Stop Immediate Propagation: https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation
As a brave editor says, you can also pass false as a third argument to the addEventListener and it does basically the same thing but is less comprehensible and does some additional things as well, so I have opted not to default to this just because its easier to understand that you are stopping propagation.
I made a jsfiddle that does it:
https://jsfiddle.net/zgqpnaey/
var elems = window.document.getElementsByTagName('*');
for (var i = 0; i < elems.length; i++) {
myFunction(elems[i]);
}
function myFunction(element) {
element.onclick = function(e) {
e.preventDefault();
e.cancelBubble = true;
if (e.stopPropagation) e.stopPropagation();
element.style.background = 'red';
};
}
somethinghere explained it above.
Also, you shouldn't bind onclick inside a loop, it's known to cause errors; it's better to call a function and pass the proper parameters.
when i use the .preventDefault on a link it still goes to the link - also is this even doable with JS or is it a jquery only method?
var avoidlink = getElementsByTagName("a");
avoidlink.addEventListner("click",function(evt){
evt.preventDefault();
},false);
Click here
Three problems :
getElementsByTagName must be called on the document or on an element
You can't add an event listener directly on the node list returned by getElementsByTagName, you must iterate over the elements it contains :
you have a typo in addEventListener
Here's a fixed code :
var avoidlink = document.getElementsByTagName("a");
for (var i=0; i<avoidlink.length; i++) {
avoidlink[i].addEventListener("click",function(evt){
evt.preventDefault();
},false);
}
If you want to be able to attach an event listener to a node list, you may enrich NodeList.prototype :
NodeList.prototype.addEventListener = function(){
for (var i=0; i<this.length; i++) {
Element.prototype.addEventListener.apply(this[i] , arguments);
}
}
Demonstration
Modifying the prototype of objects you don't own is generally frowned upon but this change is rather innocuous and natural.
Usually if many elements need the same event listener you can add the event listener to the container and filter out what element you would like to take action upon:
document.addEventListener("click",function(e){
if(e.target,e.target.tagName.toLowerCase()==="a"){
e.preventDefault();
}
});
If you were to add extra anchor tags through script they will trigger the preventDefault too.
I'm working with Prototype on a script to detect all Select Tags under a Div and then add an event/observer on each one!
Here is the code to find the Elements I need:
Event.observe(window, 'load', function() {
var tab=$("product-options-wrapper").descendants();
var attCode=[];
var j=0;
for (i=0;i<tab.length;i++) {
if (tab [i].tagName =="SELECT") {
attCode[j++]=tab[i].id
}
}
});
I have all the Ids I need.
How can I add an observer (on change) for each one?
$(id).on("change", function(event) {
alert(id+"__"+$(id).value);
});
Prototype supports event delegation out of the box. Event.on takes on optional second selector parameter. So in your case:
$("product-options-wrapper").on('click', 'select', function(event, element) {
// This callback will only get fired if you've clicked on a select element that's a descendant of #product-options-wrapper
// 'element' is the item that matched the second selector parameter, in our case, the select.
....
});
That parameter can be any CSS selector string:
$('my-element').on('click', '.some-class', function(event, element) { ... });
Check out Element.select, too. That will condense the code in your original question down to essentially one line:
$("product-options-wrapper").select('select');
This one seems kind of confusing because your selector string is 'select' (you want all SELECT elements under #product-options-wrapper). You could also do:
$$('#product-options-wrapper select');
These both return an array of matched elements.
HTH
You only need a click handler on the div (in other words, use event delegation)
var tab = $("product-options-wrapper");
tab.on('click',function(e){
e = e || event;
if ( /^select$/i.test((e.target || e.srcElement || {}).tagName) ){
//do stuff
}
});
That should do. Please post your html or even better a jsfiddle if you need more help.
$(function(){
$('#product-options-wrapper select').on("change", function(e) {
alert(id+"__"+$(this).val());
});
});
I guess you forgot the . at the beginning of product-options-wrapper to indicate its a class? Or is it really a tag?
I've been struggling with what seems to be a simple problem for a few hours now. I've written a REGEX expression that works however I was hoping for a more elegant approach for dealing with the HTML. The string would be passed in to the function, rather than dealing with the content directly in the page. After looking at many examples I feel like I must be doing something wrong. I'm attempting to take a string and clean it of client Events before saving it to our Database, I thought jQuery would be perfect for this.
I Want:
Some random text click here and a link with any event type
//to become:
Some random text click here and a link with any event type
Here's my code
function RemoveEvilScripts(){
var myDiv = $('<div>').html('testing this Do it! out');
//remove all the different types of events
$(myDiv).find('a').unbind();
return $(myDiv).html();
}
My results are, the onClick remains in the anchor tag.
Here's a pure Javascript solution that removes any attribute from any DOM element (and its children) that starts with "on":
function cleanHandlers(el) {
// only do DOM elements
if (!('tagName' in el)) return;
// attributes is a live node map, so don't increment
// the counter when removing the current node
var a = el.attributes;
for (var i = 0; i < a.length; ) {
if (a[i].name.match(/^on/i)) {
el.removeAttribute(a[i].name);
} else {
++i;
}
}
// recursively test the children
var child = el.firstChild;
while (child) {
cleanHandlers(child);
child = child.nextSibling;
}
}
cleanHandlers(document.body);
working demo at http://jsfiddle.net/alnitak/dqV5k/
unbind() doesn't work because you are using inline onclick event handler. If you were binding your click event using jquery/javascript the you can unbind the event using unbind(). To remove any inline events you can just use removeAttr('onclick')
$('a').click(function(){ //<-- bound using script
alert('clicked');
$('a').unbind(); //<-- will unbind all events that aren't inline on all anchors once one link is clicked
});
http://jsfiddle.net/LZgjF/1/
I ended up with this solution, which removes all events on any item.
function RemoveEvilScripts(){
var myDiv = $('<div>').html('testing this Do it! out');
//remove all the different types of events
$(myDiv)
.find('*')
.removeAttr('onload')
.removeAttr('onunload')
.removeAttr('onblur')
.removeAttr('onchange')
.removeAttr('onfocus')
.removeAttr('onreset')
.removeAttr('onselect')
.removeAttr('onsubmit')
.removeAttr('onabort')
.removeAttr('onkeydown')
.removeAttr('onkeypress')
.removeAttr('onkeyup')
.removeAttr('onclick')
.removeAttr('ondblclick')
.removeAttr('onmousedown')
.removeAttr('onmousemove')
.removeAttr('onmouseout')
.removeAttr('onmouseover')
.removeAttr('onmouseup');
return $(myDiv).html();
}
Why is this "copy"(click) wrong, it binds all the previous handlers as well:
var add = function(element) {
var ele = element.clone(true);
$('.container').append(ele);
$('.copy', new).click(function(){ add(ele); });
}
Idea: I want to have an element text next to a "copy" button.
When I click "copy", it clones the current row and append it to the container.
But this seems to be recursive...
The true parameter says:
Normally, any event handlers bound to the original element are not copied to the clone. The optional withDataAndEvents parameter allows us to change this behavior, and to instead make copies of all of the event handlers as well, bound to the new copy of the element.
So you keep adding click event handlers to the .clone element. Depending on your actual case, just don't bind the event handler again:
var add = function(element) {
var cloned = element.clone(true);
$('.container').append(cloned);
}
$('.container .copy').click(function(){
add($(this).closest('tr'));
});
(I used $(this).closest('tr') to get the parent row. Obviously you have to adjust it to your needs.)
Update:
Or don't pass true:
var add = function(element) {
var cloned = element.clone();
$('.container').append(cloned);
$('.copy', cloned).click(function(){ add(cloned); });
}
new is JS keyword. Change it to something else and it should work.
( Your code does not have call of add() except of from itself. So it is not clear how code gets there initially. And recursive declaration of functions as in your code is a path to programmers hell )