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.
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.
So say I have some code that creates an indefinite number of comments in a main section of the page, such as
function createcomments(comments) {
var main = document.getElementById("main");
for (var i = 0; i < comments.length; i++) {
var comment = document.createElement("quoteblock");
comment.innerHTML = comments[i];
main.appendChild(comment);
comment.classList.add("comment");
}
}
And every time a visitor to my page hovered over a comment the background would turn red or something:
window.onload = function() {
var comments = document.querySelectorAll(".comment");
// code for handling .onmouseover and .onmouseout
// for each element in the array
}
How would I do that? I think there is a way to do it with jQuery, but I was wondering if there's a way to do it with JavaScript.
In jQuery there are this two helper functions delegate() and live().
They work as nicely described in this blog post.
Actually you can attach an eventHandler to a parent element that is than listeing to all mouse events (and other events). Using delegation you then check on the parent elements eventHandler if the event is coming from a specific child.
<ul>
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
here we add some simple html, but we dont attach to the span element for a click handler, but to the div. in the div eventHandler we then check, what target actually got clicked
var divs = document.querySelector("ul");
divs.addEventListener("click", function(ev) {
if (ev.target.tagName === "LI")
console.log("A list element (" + ev.target.innerText + ") was clicked");
});
The whole reason behind this delegation is performance. also, if you remove or add items dynamically, the event handling works as expected without any additional work.
If you dont want to use the whole jQuery for this simple step, I still suggest you use some framework, as it is always better to use community support than reinventing the wheel
try http://craig.is/riding/gators, looks nice :)
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'));
});
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 )