Can someone tell me why the javascript code below causes renewSession() to be called 7 times after a single click?
$(document).ready(function () {
$("*").mouseup(function () {
renewSession();
});
});
function renewSession() {
$.ajax({
url: "/Account/RenewSession",
type: "POST"
});
}
Probably it's because the mouseup event propagates up through the DOM tree, and you're applying the handler to every element in the document. So it'll fire on the first element, and then the parent and so on until it gets to the html (or the body, I can never quite remember without checking every time).
You could use:
$(document).ready(function () {
$("*").mouseup(function (e) {
e.stopPropagation();
renewSession();
});
});
To prevent the multiple calls.
Edited to address comment from thiag0:
Thanks for the quick response...what I am trying to do is call renewSession() every time the user clicks on the site to keep the session alive. This solution prevents the renewSession from getting called multiple times in a single click but prevents the actual intent of the user's click from firing. Anyway to get around this?
You could just target the body element; so long as events are allowed to propagate through the DOM tree (so long as you're not calling event.stopPropagation() on elements between the element clicked on (or 'mouseup'-ed) then the event(s) will propagate to the body. So I'd suggest using:
$(document).ready(function () {
$("body").mouseup(function () {
renewSession();
});
});
The * selctor matches 7 elements...
Events in html bubble up the DOM tree, unless explicitly told to stop, and hence the event will be triggered for each element going up the tree that matches the selector (in this case all of them!).
If this is not your intended behaviour either use a more specific selector, or call the stopPropagation method.
Related
I just want to prevent to open a new page when click a link(it may be a img or button). And here is the code in my "content-scripts.js":
document.onclick = function() {
return false;
}
It can work but sometimes it doesn't work and I don't know why. When I click some elements on the web page, it will still open another url.
It doesn't always work because a click may not make it all the way to document, its bubbling may be cancelled before it gets there.
To do what you're doing, you'd have to hook click on every element on the page, and list for DOM modifications so that you can hook click on new elements if they're added to the page.
To process all elements, you can either walk the DOM tree recursively or get one potentially-massive list via document.querySelectorAll("*").
To listen for DOM modifications so you can hook new elements as they're added, you'd want a mutation observer.
Because other JavaScript code may overwrite your onclick, I'd use addEventListener instead, and both stop propagation and stop immediate propagation:
function stopEvent(e) {
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
}
someElement.addEventListener("click", stopEvent);
So for instance, roughly:
function stopEvent(e) {
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
}
document.querySelectorAll("*").forEach(function(element) {
element.addEventListener("click", stopEvent);
});
...and then use a mutation observer to handle newly-added elements.
I have the next problem.
I have different behaviours of <a> elements. I have a controller which handle 2 events:
$scope.$on("$destroy", function () {
console.log("$destroy");
});
$scope.$on("$locationChangeStart", function () {
console.log("$locationChangeStart");
});
Sometimes $locationChangeStart event fired first, but sometimes $destroy event fired first.
I need to prevent changing page, so I need $locationChangeStart to be fired first.
Please, someone has any thoughts, why different <a> have different sequence of events?
UPD
I use the same <a> element in different parts of page
test
If you want to prevent changing page it doesn't matter which one is launch first.
In your $locationChangeStart add the event object:
$scope.$on("$locationChangeStart", function (event) {
event.preventDefault(); // will prevent the location change
});
I have a button being created after the DOM is created. That button has an action. What I'm having trouble is binding that action to the button. I have researched and people said to us the .on() function but it doesn't seem to be working. What am I missing?
http://jsfiddle.net/e7a4X/
HTML
<button id="firstClick">Click me to create another button</button>
<div id="container"></div>
Javascript
$('#firstClick').click(function() {
$('#container').append('<button class="second-button">Button after DOM</button>');
});
$('.second-button').on('click', function () {
alert("Success");
})
Working demoL http://jsfiddle.net/Metsx/ or http://jsfiddle.net/ZB2Ns/
API : .on http://api.jquery.com/on/
Now to make your event know about the click event you need .on at document or at #container level, which attaches event handlers to the currently selected set of elements in the jQuery object.
Rest should fit your need :)
Code
$('#firstClick').click(function() {
$('#container').append('<button class="second-button">Button after DOM</button>');
});
$(document).on('click', '.second-button', function () {
alert("Success");
})
You will need to tell the DOM, parent to listen to its child.
The issue is that Your new .second-button is a new element, and you have defined your .click function before the DOM actually exists.
But all DOM interactions will trigger a event propagations(bubbling), therefore you can tell #container to listen for click events coming from .second-button
Or use $(document).on to listen, since the bubbling will go all the way to the document root.
If you are a performance minimalist than you would just do #container .on, and stop the propagation from that point, since theres no need to travel to every parent node, but you might eventually need to listen it from the parent of the #container, who knows
i'm trying to register the second click on a link, by adding a new class and finding it with jQuery. But it won't change the class after the 1st click.
Hope it makes sense and thank you in advance.
// Listen for when a.first-choice are being clicked
$('.first-choice').click(function() {
// Remove the class and another one
$(this).removeClass('first-choice').addClass('one-choice-made');
console.log('First Click');
// Some code goes here....
});
// Make sure the link isn't fireing.
return false;
});
// Listen for when a.one-choice-made are being clicked
$('.one-choice-made').click(function() {
// Remove the class and another one
$(this).removeClass('one-choice-made').addClass('two-choice-made');
console.log('Second Click');
// Some code goes here....
});
// Make sure the link isn't fireing.
return false;
});
At load, .one-choice-made does not exist, so when you call $('.one-choice-made'), it returns an empty jQuery object, hence the click() handler is not added to anything.
What you want to do is attach the handler to something that will always exist, which will respond to the click event (i.e. a parent/ancestor element). This is what $.on() will do for you when called in a delegated handler syntax (i.e. with a filter selector):
$(document).on('click', '.one-choice-made', function() {
// my second function
}
In this case, jQuery attaches a special handler to document, which watches for click events that propagate to it from children elements. When it receives a click, jQuery looks at the target of the click and filters it against the selector you provide. If it matches, it calls your function code. This way, you can add new elements with this class at any time, as long as they are children of the elements from the selector(s) you applied .on() to. In this case, we used document, so it will always work with new elements.
You can pare this down to a known permanent parent element to reduce click events, but for simple cases document is fine.
NOTE: In the same way, removing the class first-choice will not have any affect on whether the first click handler is called, because the handler is applied to the element. If you remove the class, the element will still have the handler. You will need to use a delegated handler for that as well:
$(document).on('click', '.first-choice', function() {
// my first function
}
Demo: http://jsfiddle.net/jtbowden/FxqX9/
Since you're changing the class you need to use .on()s syntax for delegated events.
Change:
$('.one-choice-made').click(function() {
to:
$(document).on('click', '.one-choice-made', function() {
Ideally you want to use an element already in the DOM that's closer than document, but document is a decent fallback.
Whats the easiest way to temporarily disable all mouse click/drag etc events through javascript?
I thought I could do document.onclick = function() { return false; }; ...etc, but that's not working.
If the objective is to disable click on the whole page then you can do something like this
document.addEventListener("click", handler, true);
function handler(e) {
e.stopPropagation();
e.preventDefault();
}
true argument in addEventListener would ensure that the handler is executed on the event capturing phase i.e a click on any element would first be captured on the document and the listener for document's click event would be executed first before listener for any other element. The trick here is to stop the event from further propagation to the elements below thus ending the dispatch process to make sure that the event doesn't reach the target.
Also you need to stop default behavior associated with event target elements explicitly as they would be executed by default after the dispatch process has finished even if the event was stopped propagating further from above
It can be further modified to use selectively.
function handler(e) {
if(e.target.className=="class_name"){
e.stopPropagation();
e.preventDefault();
}
}
handler modified this way would disable clicks only on elements with class "class_name".
function handler(e) {
if(e.target.className!=="class_name") {
e.stopPropagation()
}
}
this would enable clicks only on elements with class "class_name".
Hope this helped :)
Dynamically disable all clicks on page
let freezeClic = false; // just modify that variable to disable all clics events
document.addEventListener("click", e => {
if (freezeClic) {
e.stopPropagation();
e.preventDefault();
}
}, true);
I often use it while loading or to avoid user to accidentally clic twice on an action button. Simple and performance friendly :)
Please check this working example
Alternative CSS way
Another one that I really like because of the visual feedback the user have:
/* style.css */
.loading {
cursor: wait; /* busy cursor feedback */
}
.loading * {
/* disable all mouse events on children elements */
pointer-events: none;
}
A simple example to dynamically add the .loading class:
const elm = document.getElementById('myElm')
elm.classList.add('loading')
myAsyncFunction().then(() => elm.classList.remove('loading'))
If you want absolutely nothing draggable/clickable, disabling typing in input fields etc, I'd consider showing a absolutely positioned transparent div over the entire page, so that every click will be on the div, which will do nothing. That will grant you swift and neat switching on and off of this click-disabler, without having to register heaps of listeners
The winning answer works well, but if you had pass the capture true boolean value, at the moment you want to remove the listener, you have to pass the exact same value. Otherwise, the listener removal will not work.
Example:
listener addition
document.addEventListener('click', DisableClickOnPage.handler, true);
listener removal
document.removeEventListener('click', DisableClickOnPage.handler, true);
Doc: https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener
window.addEventListener("click", (e) => {
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
}, true)
If we added a listener to document instead of window anyone can add a listener to window and it works. Because of document child of window and its events trigger always after window events.
We use 3 method of Event object.
stopPropagation for prevent all capturing and bubbling
stopImmediatePropagation for prevent same listeners (e.g. another window click listeners)
preventDefault for prevent all user agent event (e.g anchor href or form submit)
If onclick = null has been executed how to revoke the onclick event to normal functioning.. or
Link text
<script type="text/javascript">
function yourFunction(anchor)
{ if(anchor.disabled) return;
/* Your function here */
}
</script>
This article would probably be useful:
http://www.computerhowtoguy.com/how-to-use-the-jquery-unbind-method-on-all-child-elements/
One part in particular is a recursive function that removes all click events. Remember that jQuery will remove click events IF the click event was created using jQuery. the function given in the article will remove both those created with jQuery and those that were not. The function given is this:
function RecursiveUnbind($jElement) {
// remove this element's and all of its children's click events
$jElement.unbind();
$jElement.removeAttr('onclick');
$jElement.children().each(function () {
RecursiveUnbind($(this));
});
}
You would call the function like this:
RecursiveUnbind($('#container'));
That function takes a jQuery object parameter, but you could easily change it up to pass a string as the name of the ID for the element, or however you think is best.
To prevent the default behavior of an event, use event.stopPropagation() and event.preventDefault() in your event handler. And don't forget, return false; is another method for indicating that you want to cancel the default action...
The Event property returnValue indicates whether the default action for this event has been prevented or not. It is set to true by default, allowing the default action to occur. Setting this property to false prevents the default action. (Source: MDN Web Docs: Event.returnValue.)
Typically, we return a value from any function when it has any meaningful or useful purpose -- return false to cancel an event is meaningful because it indicates a failed event, and it's useful because the event-handler uses it.
For greatest cross-browser compatibility, remember to return false;...
document.addEventListener("click",handler,true);
function handler(e){
e.stopPropagation();
e.preventDefault();
return false;
}