javaScript - remove event from certain links - javascript

I can't figure out how to remove an event listener from an element on my page. This event is causing issues between two scripts and it would be great to get rid of it!
Here's how it's added;
if (CT_I_EnableExitTracking) {
if (document.addEventListener) //handle DOM 2 (Mozilla 6)
document.addEventListener('click', CT_ProcClick, false);
else
document.attachEvent('onclick', CT_ProcClick);
}
..and it needs removing from this markup (from the flexslider 2 plugin)..
<ul class="flex-direction-nav">
<li><a class="flex-prev" href="#">Previous</a></li>
<li><a class="flex-next" href="#">Next</a></li>
</ul>
The links inside this div are the issue. How can I target them? I've tried various ideas but I just don't seem to get the syntax right (too much time with jQuery and no real jS knowledge I think!!)
var prev = document.getElementsByClassName("flex-prev");
prev.removeEventListener('click', CT_ProcClick, false);
Thanks!

You're assigning event listener to document object while you try to remove event listener from flex-prev.
In addition, document.getElementsByClassName("flex-prev") returns a NodeList. In this case you should either loop that through:
[].forEach.call(prev, function(obj, i) { ... });
or reference to single instance with:
document.getElementsByClassName("flex-prev")[0].
But in your case, you should make a check on the event listener's function whether the event.target has class "flex-prev". Like this:
function CT_ProcClick(evt) {
var target = evt.target || evt.srcElement;
if (!!~target.className.indexOf("flex-prev")) {
return false;
}
...
}

Related

get element by tag name [this]?

First a short background. So I just started practicing using API's. With the one I'm working with right now, I'm loading a DIV which have alot of links in it which I have to give a new purpose. I managed to prevent the default onclick-function. Now I need do save the clicked link "innerHTML" attribute.
var nextPage = document.getElementsByTagName("a")[this].innerHTML;
with [this] I tried to target the clicked link, but it didn't work. Hopefully you understands what I'm trying to do. If so, is there any way I an solve this problem?
Thanks!
EDIT:
$("#content, a").click(function(event){
event.preventDefault();
var x = document.getElementsByTagName("a")[0].innerHTML;
console.log(x)
getPage(x);
});
You can add an onclick listener to all the a tags elements
var links = document.getElementsByTagName('a');
for (var i = 0, il = links.length; i < il; i++) {
links[i].onclick = clickHandler;
}
function clickHandler(event) {
console.log(this.innerHTML);
}
<a>Link a</a>
<a>Link b</a>
first the document.getElementsByTagName("a")[this].innerHTML; will return undefined because it will return a collection of html node and it must pass index not the this.
Since you already have a click you can try this code :
function yourClickFunction(event) {
var target = event.target || event.srcElement;
var nextPage = target.innerHTML;
}
Use jQuery for this:
$('a').on('click', function(){
// this will run with every click, and 'this' will be your clicked item
console.log(this.innerHTML);
// although you probably want:
console.log($(this).attr('href'));
});
Using jQuery makes your code much cleaner, and unifying the cross browsers compatibility issues you might have when handling directly with the DOM api.
this.innerHTML can do the work, if I am getting you correctly.
If you are getting the entire html in it, you can bind an onclick event to the anchor itself and can work on that if that is possible.
<a onclick="clicked(this)">Click me</a>
function clicked(element) {
// Do whatever needed
// element.innerHTML will change it's innerHTML
}
You can it like the following too
$("#content, a").click(function(event){
event.preventDefault();
event.target.innerHTML = "Whatever";
})
You could use a common class (link in the below example) to attach the click event then just use this.innerHTML to return the text of you clicked link.
Hope this helps.
var classname = document.getElementsByClassName("link");
var clickFunction = function(){
//Prevent default
if ( event.preventDefault ) event.preventDefault();
event.returnValue = false;
//Get text
console.log(this.innerHTML);
}
for(var i=0;i<classname.length;i++){
classname[i].addEventListener('click', clickFunction, false);
}
<a href='link-1' class='link'>Link 1</a>
<a href='link-2' class='link'>Link 2</a>
<a href='link-3' class='link'>Link 3</a>
document.getElementsByTagName("a") gives you an array of HTMLAnchorElement. The indexes of the array are integer values from 0 to n.
this in your context i think it's the windows object (your code example is a bit short so i have to guess a bit)
using window as the index for the array that expects an integer of course gives you nothing. or undefined to be precise.
There're two possible ways to do what you're looking for:
onclick handler
function hello(elem) {
console.log("you clicked on '" + elem.innerHTML + "'")
}
click me
Here i'm using the onclick property and I pass the this context from the html as an argument to the function i'm calling. This is important.
Now i can operate on the element that was clicked just by referencing the argument received.
I would not suggest this method for a number or reasons. But since you mention the onclick property in the question ...
click event handler
this would be my preferred solution
function hello(evt) {
var elem = event.target || event.srcElement;
console.log("you clicked on '" + elem.innerHTML + "'");
}
var link = document.getElementsByTagName("a")[0]
link.addEventListener("click", hello)
click me
Here there's no code (or reference to the code) in the html. You instead retrieve the HTMLAnchorElement from the code and attach a listener to the click event.
Now the event handler will be called whenever the link is clicked and it will receive an event object by default. From that object you can extract the target (the object that generated the event) and access its properties.

Jquery get list value without parent

I have this code that for now creates a Alert() with the value of that list item.
Now when i click a list item that has another list item as parent. it will alert() them both.
$("#nav li").click(function() {
$LiValue = this.value;
alert($LiValue);
});
Example. here is the HTML
<li value="1">Home</li>
<li value="2">Information
<ul class="subs">
<li value="3">History</li>
<li value="4">Present</li>
<li value="5">Future</li>
</ul>
</li>
Now when i click on list item "Information" it will return with value 2
When i click on list item "Present" it will return value 4 and then 2.
How can i only return the list item i click on and not the parent?
--------->>>> SOLVED!! (can't accept answer yet)
Thank you all for helping me. i will accept the answer as soon as i can. thank you!
Events in JavaScript naturally bubble up the DOM tree, from child elements to their ancestors. You can stop this behavior by stopping the event propagation.
$("#nav li").click(function(e) {
e.stopPropagation();
$LiValue = this.value;
alert($LiValue);
});
The fix to your problem is stopPropagation(). The jQuery documentation tells you that this function "Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event."
Basically, the event will not be fired for any of the parent elements. In order to use this method, handle the first parameter that your click function provides you. Then you call the method inside the function. Your method should look like this
$("#nav li").click(function(e) {
e.stopPropagation()
$LiValue = this.value;
alert($LiValue);
});
$("#nav li").click(function(e) {
$LiValue = this.value;
alert($LiValue);
return false;
});
or try to add return false.
Explanation : The difference is that return false; takes things a bit further in that it also prevents that event from propagating (or "bubbling up") the DOM. The you-may-not-know-this bit is that whenever an event happens on an element, that event is triggered on every single parent element as well.
So in other words:
function() {
return false;
}
// IS EQUAL TO
function(e) {
e.preventDefault();
e.stopPropagation();
}
see this link for further explanation

How to handle an indefinite number of events?

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 :)

how to remove all ClientEvents from anchors in an HTML String with jQuery

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();
}

Make (possibly dynamically loaded) element clickable via JavaScript, but give precedence to links contained within

I am adding a custom data attribute data-js-href to various HTML elements, and these elements should behave just like a link when clicked. If a link within such an element is clicked, the link should take precedence and the data-js-href functionality should be ignored, though. Furthermore, the solution also needs to work with elements that are dynamically added at a later time.
So far, I have come up with the following solution. It basically checks if the click was performed on a link, or any child element of a link (think <a href='…'><img src='…' alt='…' /></a>).
// Make all elements with a `data-js-href` attribute clickable
$$('body').addEvent('click:relay([data-js-href])',
function(event, clicked) {
var link = clicked.get('data-js-href');
if (link && !event.target.match('a')) {
var parents = event.target.getParents();
for (var i = 0; i < parents.length && parents[i] != clicked; i++) {
if (parents[i].match('a')) {
return;
}
}
document.location.href = link;
}
});
It works, but it feels very clumsy, and I think that there has to be a more elegant solution. I tried something along the lines of
$$('body').addEvent('click:relay([data-js-href] a)',
function(event, clicked) {
event.stopPropagation();
}
but to no avail. (I littered the code with some console.log() messages to verify the behavior.) Any idea is welcome.
you can do this with 2 delegated events - no reverse lookups and it's cheap as they will share the same event. the downside is, it is the same event so it will fire for both and there's no stopping it via the event methods (already bubbled, it's a single event that stacks up multiple pseudo event callbacks and executes them in order--the event has stopped but the callbacks continue) That's perhaps an inconsistency in mootools event vs delegation implementation but it's a subject of another issue.
Workarounds for now can be:
to have the 2 event handlers communicate through each other. It will scale and work with any new els added.
to add the delegators on 2 different elements. eg. document.body and #mainWrap.
http://jsfiddle.net/dimitar/J59PD/4/
var showURL = function(howLong) {
// debug.
return function() {
console.log(window.location.href);
}.delay(howLong || 1000);
};
document.id(document.body).addEvents({
"click:relay([data-js-href] a))": function(e) {
// performance on lookup for repeat clicks.
var parent = this.retrieve("parent");
if (!parent) {
parent = this.getParent("[data-js-href]");
this.store("parent", parent);
}
// communicate it's a dummy event to parent delegator.
parent.store("linkEvent", e);
// let it bubble...
},
"click:relay([data-js-href])": function(e) {
// show where we have gone.
showURL(1500);
if (this.retrieve("linkEvent")) {
this.eliminate("linkEvent");
return;
}
var prop = this.get("data-js-href");
if (prop)
window.location.href = prop;
}
});
Discussed this with Ibolmo and Keeto from the mootools team on IRC as well when my initial attempt failed to work and both callbacks fired despite the event.stop: http://jsfiddle.net/dimitar/J59PD/
As a result, there was briefly a ticket open on the mootools github issues: https://github.com/mootools/mootools-core/issues/2105 but it then went into a discussion of what the right thing to do from the library standpoint is and how viable it is to pursue changing the way things work so...

Categories