Can someone explain me, how to improve my code, so that it will:
Not call beforeunload event if I'll click on button with class
.btn?
And, if it's possible, without tracking each click event.
I mean:
$(document).on("click", ....);
Here's my current code. It's working, but it prevents page reloading on each action (close, back, click on any button etc)
var reload = $(document).find("[data-prevent-reload]");
if(reload.data('prevent-reload')) {
window.addEventListener('beforeunload', function (ev) {
return ev.returnValue = 'STOP!';
});
}
There is no event that tells you what triggered it so you are stuck with listening to the click events. It is normally done with boolean and check it before calling it.
var ignoreUnload
$(document).on("click", ".btn", function () {
ignoreUnload = true
});
window.addEventListener('beforeunload', function (ev) {
if(!ignoreUnload) return ev.returnValue = 'STOP!';
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a class="btn" href="https://example.com">btn</a>
<a class="" href="https://example.com">not</a>
other option could be to unbind the event instead of the boolean.
Related
Here's my situation:
I have a custom menu on right mouse click for my project. Here, I have document.addEventListener on click, that makes this menu invisible, like this:
var i = document.getElementById("menu").style;
document.addEventListener('click', function(e) {
i.opacity = "0";
setTimeout(function() {
i.visibility = "hidden";
}, 100);
}, false);
And it's great, works well, but I'm implementing a dropdown submenu that should be opened when you click on a certain element, like so:
$('#change_color').click(function(){
if($('#back_color').hasClass('back_color')){
$('#back_color').removeClass('back_color')
}else{
$('#back_color').addClass('back_color')
}
})
The thing is that when I click on that #change_color then addEventListener is firing, which is obvious.
The question is – how can I prevent that listener function to execute when I click on #change_color?
You can prevent further propagation of the current event in the capturing and bubbling phases using event.stopPropagation() and for simplicity in your code use jQuery.toggleClass().
Code example:
$('#change_color').click(function (e) {
$('#back_color').toggleClass('back_color');
e.preventDefault();
e.stopPropagation();
});
On a click function I have the option of playing audio.
The click is only fired once (after I added .off(), which I seem to have to do for every click event because I think there's something I fundamentally don't get about how javascript works) but the function added to the "ended" listener shows it is firing the number of times the button has been clicked. I presume .play() is also being fired multiple times.
These need to be inside the click event to get the id so how do I stop these kinds of things from happening, here and elsewhere when using js? Adding event.stopPropagation(), event.bubbles = false and .off() everywhere seems unnecessary (and in this case doesn't make a difference anyway).
$('.button').off().on('click', function(event){
event.stopPropagation();
event.bubbles = false;
var id = $(this).attr('id')
if ($(this).hasClass('hasAudio')) {
document.getElementById('audio_'+id).play();
document.getElementById('audio_'+id).addEventListener("ended", function(){
console.log("ended");
});
}
});
Move the ended event outside the click event,you are registering the event each time you click on the button
$('.button').on('click', function(event){
var id = $(this).attr('id')
if ($(this).hasClass('hasAudio')) {
document.getElementById('audio_'+id).play();
}
});
$('[id^="audio_"]').on("ended", function(){
console.log("ended");
});
Each time you click on the button a new event listener will be added to the ended event. To prevent that you can try defining the callback function before hand. That will prevent your event listener to be added in the event loop over and over.
An anonymous function has no signature, hence when you define the event with it, it will think that this is supposed to be a new event listener and invokes it multiple times. Check the working snippets to see the difference. Type something in the input box to see what is happening.
If this is confusing then removeEventListener can be the next option.
function ended(event){
console.log("ended");
}
$('.button').off().on('click', function(event){
event.stopPropagation();
event.bubbles = false;
var id = $(this).attr('id')
if ($(this).hasClass('hasAudio')) {
document.getElementById('audio_'+id).play();
document.getElementById('audio_'+id).addEventListener("ended", ended);
}
});
var input = document.getElementById('some');
function callback(event) {
console.log("PRINT");
}
input.addEventListener("keyup", callback)
// input.removeEventListener("keyup", callback)
input.addEventListener("keyup", callback)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="some" value="" >
Anonymous function as callback
var input = document.getElementById('some');
input.addEventListener("keyup", function(event) {
console.log("PRINT");
})
// input.removeEventListener("keyup", callback)
input.addEventListener("keyup", function(event) {
console.log("PRINT");
})
<input id="some" value="">
This fails because, every time you click the function, you add a new event listener to the button.
document.getElementById('audio_'+id).addEventListener("ended", function(){
console.log("ended");
This is repeatedly adding the event listener to the button.If you need this inside the click event, check to see whether it exists already. If it does, don't add it again.
Use global flag which defines if you want to pause or play. and also use preventDefault (in case of any inline click event used).
You have to remove the registered event listener after your task is completed.
document.getElementById('audio_'+id).removeEventListener("ended", function(){
console.log("ended");
});
Or what you can do is that move the logic for registering event listener outside the click event listener. Like this the event will be registered only once.
document.getElementById('audio_'+id).addEventListener("ended", function(){
console.log("ended");
});
}
$('.button').off().on('click', function(event){
event.stopPropagation();
event.bubbles = false;
var id = $(this).attr('id')
if ($(this).hasClass('hasAudio')) {
document.getElementById('audio_'+id).play();
});
Anybody know how to detect browsers refresh and back button events in firefox using jquery or javascript.
For back button:
window.addEventListener('popstate', function (event) {
//Your code here
});
For Refresh:
window.onbeforeunload = function () {
// Your code here
}
You can try WindowEventHandlers.onbeforeunload:
window.onbeforeunload = function(e) {
};
and
$(window).unload(function() {
//
});
Also check Browser Back Button Detection:
I have made a very reusable javascript class, that can be simply
dropped into your web page, and when the user clicks back, it will
call a function. The default function on this call is a javascript
alert “Back Button Clicked”.
To replace this functionality, you simply need to override the OnBack
function. This can be done by using the code below.
<script type="text/javascript">
bajb_backdetect.OnBack = function()
{
alert('You clicked it!');
}
</script>
This will now replace the “Back Button Clicked” alert with a “You
clicked it!’” alert.
Check this page: Manipulating the browser history
You can probably get something working with using history.pushState and window.onpopstate
You can use the following events:
window.onpopstate for back button press.
window.onpopstate = (e) => {
// your logic goes here
};
window.onbeforeunload for refresh or tab close.
window.onbeforeunload = (e) => {
// your logic here
e.preventDefault();
e.returnValue = 'There are unsaved changes. Sure you want to leave?';
};
This question already has answers here:
What's the difference between event.stopPropagation and event.preventDefault?
(8 answers)
Closed 7 years ago.
Firstly, in JavaScript's event model, you will come
across a concept called as event bubbling
(which makes an event to propagate from child
element to a parent element). In order to avoid
such kind of bubbling effect, many developers
use an event method called stopPropagation( ).
Alternatively, developers have started to use
return false statement to stop such propagation.
Now, there is another terminology called
preventDefault( ). As the name indicates, this
method prevents any default behavior of an
element to trigger. Best use case is to prevent an
anchor tag to open a link.
You may come across a scenario where you
would like to prevent the anchor tag from
opening a link (default behavior) as well as stop
the event from going up to the parent.
In such situation, instead of writing two lines of code,
you can get it done in single line i.e; return false
return false;
return false; does 3 separate things when you call it:
event.preventDefault() – It stops the browsers default behaviour.
event.stopPropagation() – It prevents the event from propagating (or “bubbling up”) the DOM.
Stops callback execution and returns immediately when called.
Note that this behaviour differs from normal (non-jQuery) event handlers, in which, notably, return false does not stop the event from bubbling up.
preventDefault();
preventDefault(); does one thing: It stops the browsers default behaviour.
When to use them?
We know what they do but when to use them? Simply it depends on what you want to accomplish. Use preventDefault(); if you want to “just” prevent the default browser behaviour. Use return false; when you want to prevent the default browser behaviour and prevent the event from propagating the DOM. In most situations where you would use return false; what you really want is preventDefault().
Examples:
Let’s try to understand with examples:
We will see pure JAVASCRIPT example
Example 1:
<div onclick='executeParent()'>
<a href='http://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
function executeChild() {
alert('Link Clicked');
}
function executeParent() {
alert('div Clicked');
}
</script>
Run the above code you will see the hyperlink ‘Click here to visit
stackoverflow.com‘ now if you click on that link first you will get
the javascript alert Link Clicked Next you will get the javascript
alert div Clicked and immediately you will be redirected to
stackoverflow.com.
Example 2:
<div onclick='executeParent()'>
<a href='http://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
function executeChild() {
event.preventDefault();
event.currentTarget.innerHTML = 'Click event prevented'
alert('Link Clicked');
}
function executeParent() {
alert('div Clicked');
}
</script>
Run the above code you will see the hyperlink ‘Click here to visit
stackoverflow.com‘ now if you click on that link first you will get
the javascript alert Link Clicked Next you will get the javascript
alert div Clicked Next you will see the hyperlink ‘Click here to
visit stackoverflow.com‘ replaced by the text ‘Click event prevented‘
and you will not be redirected to stackoverflow.com. This is due > to event.preventDefault() method we used to prevent the default click
action to be triggered.
Example 3:
<div onclick='executeParent()'>
<a href='http://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
function executeChild() {
event.stopPropagation();
event.currentTarget.innerHTML = 'Click event is going to be executed'
alert('Link Clicked');
}
function executeParent() {
alert('div Clicked');
}
</script>
This time if you click on Link the function executeParent() will not
be called and you will not get the javascript alert div Clicked
this time. This is due to us having prevented the propagation to the
parent div using event.stopPropagation() method. Next you will see the
hyperlink ‘Click here to visit stackoverflow.com‘ replaced by the text
‘Click event is going to be executed‘ and immediately you will be
redirected to stackoverflow.com. This is because we haven’t prevented
the default click action from triggering this time using
event.preventDefault() method.
Example 4:
<div onclick='executeParent()'>
<a href='http://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
function executeChild() {
event.preventDefault();
event.stopPropagation();
event.currentTarget.innerHTML = 'Click event prevented'
alert('Link Clicked');
}
function executeParent() {
alert('Div Clicked');
}
</script>
If you click on the Link, the function executeParent() will not be
called and you will not get the javascript alert. This is due to us
having prevented the propagation to the parent div using
event.stopPropagation() method. Next you will see the hyperlink ‘Click
here to visit stackoverflow.com‘ replaced by the text ‘Click event
prevented‘ and you will not be redirected to stackoverflow.com. This
is because we have prevented the default click action from triggering
this time using event.preventDefault() method.
Example 5:
For return false I have three examples and all appear to be doing the exact same thing (just returning false), but in reality the
results are quite different. Here's what actually happens in each of
the above.
cases:
Returning false from an inline event handler prevents the browser from navigating to the link address, but it doesn't stop the event from propagating through the DOM.
Returning false from a jQuery event handler prevents the browser from navigating to the link address and it stops the event from propagating through the DOM.
Returning false from a regular DOM event handler does absolutely nothing.
Will see all three example.
Inline return false.
<div onclick='executeParent()'>
<a href='http://stackoverflow.com' onclick='return false'>Click here to visit stackoverflow.com</a>
</div>
<script>
var link = document.querySelector('a');
link.addEventListener('click', function() {
event.currentTarget.innerHTML = 'Click event prevented using inline html'
alert('Link Clicked');
});
function executeParent() {
alert('Div Clicked');
}
</script>
Returning false from a jQuery event handler.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<a href='http://stackoverflow.com'>Click here to visit stackoverflow.com</a>
</div>
<script>
$('a').click(function(event) {
alert('Link Clicked');
$('a').text('Click event prevented using return FALSE');
$('a').contents().unwrap();
return false;
});
$('div').click(function(event) {
alert('Div clicked');
});
</script>
Returning false from a regular DOM event handler.
<div onclick='executeParent()'>
<a href='http://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
function executeChild() {
event.currentTarget.innerHTML = 'Click event prevented'
alert('Link Clicked');
return false
}
function executeParent() {
alert('Div Clicked');
}
</script>
Hope these examples are clear. Try executing all these examples in a html file to see how they work.
I want to add a click handler to an ng-focus callback, to start listening to all future click events. But when focus is initiated by a click, the click handler fires immediately as well. I can solve the problem with a $timeout, but this is a hack and it goes against everything I stand for. What have I become?!
My HTML:
<input type="text" name="q" ng-focus="inputFocus($event)" />
This .js works (this is inside a directive's link function):
scope.inputFocus = function (e) {
scope.displayHistory = true;
$timeout(function () {
$document.on('click', hideHistory);
}, 200)
};
function hideHistory() {
scope.displayHistory = false;
scope.$digest();
$document.off('click')
};
I want the following to work, but the problem is that the click callback fires immediately. As you might expect, if I tab to this field, the click callback does not get called. But if the focus event is triggered by a click, hideHistory gets called.
scope.inputFocus = function (e) {
scope.displayHistory = true;
$document.on('click', hideHistory);
};
I tried calling e.stopPropagation() and e.stopImmediatePropagation() but these solutions were not effective either.
Have you tried e.preventDefault(); ?
Anyway you can provide a fiddle to illustrate exactly what's going on?