I have a button which when click will trigger to open up a popup.
<button id="thisId">OPEN POPUP</button>
The event for it will be something as follow
$(document).on('click', '#thisId', function(){
// DO SOMETHING TO OPEN THE POPUP HERE
});
This button should work as expected if the browser allows popup to be opened on it. Problem is when the popup blocker is enabled. I have quite an amount of buttons like this, probably like nearly 100 buttons with similar thing in the project that i currently working on, and i dont want to do the checking on each of the event handler for each respective buttons. I wanna make a common event handler for all the buttons, which will trigger on click of the button.
So i added another attribute to the same button
<button data-openpopup id="thisId">OPEN POPUP</button>
For this i attach an event specific to this attribute. When the button is clicked, in case if popup blocker is set on for that browser, it will do a checking to check whether popup blocker is on, and if it is, it will throw an alert to the user using jconfirm's alert box. The event for it will be something as follow
$(document).on('click', '[data-openpopup]', function(){
var $this = $(this);
var pop = window.open("about:blank", "new_window_123", "height=150,width=150");
if (!pop || pop.closed || pop.closed == "undefined" || pop == "undefined" || parseInt(pop.innerWidth) == 0 || pop.document.documentElement.clientWidth != 150 || pop.document.documentElement.clientHeight != 150){
pop && pop.close();
// Call jconfirm alert if popup is disabled
$.alert({
title: 'Popup blocked alert!',
content: 'Your popup blocker is currently enabled.',
closeIcon: true,
buttons: {
close: {
text: 'Close',
btnClass: 'btn-blue'
}
}
});
} else {
pop && pop.close();
}
});
Now the issue here is, i want it so that, when click on the button, it will override the original click method which is to open a popup, preventing it from running, and do the popup checking first. If checking is false, then only proceed with the event to open the popup.
So how can i do this?
You could use .stopImmediatePropagation() to prevent the other handler from executing.
But you have to put that in a handler that must be registered before the other(s) since the callbacks are executed in the order the listeners were registered.
If several listeners are attached to the same element for the same event type, they are called in order in which they have been added. If during one such call, event.stopImmediatePropagation() is called, no remaining listeners will be called.
Below, I "simulated" your popup blocker test with an additionnal button... Since it does not seem to be working, at least with AdBlocker Plus (Chrome extention). From what I saw, your condition is always true, AdBlocker active or not.
// To simulate a working blocker detection
var blocker=true;
$("#blockerToggle").on("click",function(){
blocker=!blocker;
$(this).find("span").text(blocker.toString().toUpperCase()).css({"color":(blocker)?"green":"red"});
}).trigger("click");
// Assuming a good popup blocker detection
// This handler can stop the others... Registered AFTER this one.
$(document).on('click', '[data-openpopup]', function(e){
if(blocker){
console.log("Blocker ON! Prevent the other listener(s) from executing.");
e.stopImmediatePropagation();
} else {
console.log("Okay, let the other listener(s) execute.");
}
});
// Other handler
$(document).on('click', '#thisId', function(){
console.log("Other handler executed.");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button data-openpopup id="thisId">OPEN POPUP</button> <button id="blockerToggle">Popup blocker active => <span></span></button>
Related
I have two or more buttons on Kendo UI Window, which all will call .close() event sooner or later after some business logic.
For example, below screen: 'Close' button will directly close the window but 'Save' button will check some condition and then trigger the close.
Now, I have added my conditions on
that.bind('close', function(){
//check some condition
// here if condition met, let the flow continue else call preventDefault()
});
This interception triggers when both the button is clicked. How do I check which button triggered the event?
FYA, I have extended the Kendo UI Window widget hence the that.bind() interception is in place.
$("#closeBtnId").bind("click", function () {
});
$("#saveBtnId").bind("click", function () {
});
try adding an event in your function and that should allow you to check who's calling that function. Something like this:
that.bind('close', function(e){
var clickedButton = e.currentTarget || e.target || e.sender;
//check some condition
// here if condition met, let the flow continue else call preventDefault()
});
How to set the Onbeforeunload Function on the specific button?
Example, I have 3 buttons.
<div>
<asp:Button ID="btnBack" runat="server" Text="Back" CssClass="po-font" Height="30px"/>
<asp:Button ID="btnSumbit" runat="server" Text="Submit" CssClass="po-font" Height="30px"/>
<asp:Button ID="btnSaveToDraft" runat="server" Text="Save To Draft" CssClass="po-font" Height="30px"/>
</div>
On javascript, I did something like:
<script type="text/javascript">
window.onbeforeunload = confirmExit;
function confirmExit()
{
return "Are you sure you want to leave this page? Any unsaved progress will be lost";
}
</script>
The function will work properly though but I want to specify the function in an specific button probably on the "Back" button. I did something like.
<script type="text/javascript">
function confirmExit()
{
return "Are you sure you want to leave this page? Any unsaved progress will be lost";
}
$('#btnBack').live('click', function () {
window.onbeforeunload = confirmExit;
});
</script>
but Id doesn't work. How to do this? Any Ideas? I just want to trigger the function on the specified button. Help me.
Use $('<%=btnBack.ClientID%>').click(function(){...}); because asp.net prefix its own client with the control id and html rendered id may look like ct100$btnBack.
First off its unlikely that the ID is correct as ASP.NET prefixes the ID with the containers if that object. Either give btnBack a class and use that or:
$("[id$='btnBack']").on("click",...)
I'll edit with a battle tested version when I'm back in front of my pc
* Edit to add battle tested code *
So you need to bind the unload event to the window, you can't assign a function to it as Kevin says in his answer. If you only want it to fire for a specific button, the code below is something I use in active production (it has a few more checks, and checks if anything has been changed on a page before firing etc...), so should work for you:
if (self == top) { // Check we're not in an iFrame or colorbox
$(window).bind("beforeunload", function (event) { // bind the window unload event
if (backLinkClicked) { // Check if the back link has been clicked, if so prompt
return "Are you sure you want to leave this page? Any unsaved progress will be lost";
};
});
}
Then your click handler:
var backLinkClicked = false;
$("[id$='btnBack']").click(function() { backLinkClicked = true });
So you back button click handler just changes the variable to fire the prompt on unload.
First off, you should understand that onbeforeunload is an event, and by putting:
window.onbeforeunload = confirmExit;
you are attaching an event handler to window, which will be global.
If I am correct, what you want is bringing up a confirmation dialog when user tries to navigate away by clicking on a button. I suggest you try this:
$('#<%=btnBack.ClientID%>').on('click', function (e) {
// check if user clicked cancel
if (!confirm("Are you sure [...]") {
e.stopImmediatePropagation();
e.preventDefault();
return false;
}
});
With this, when user clicks the button, a confirmation dialog will appear (confirm()). If user clicks cancel, code will call stopImmediatePropagation() (which should prevent other JS event handler from running) and preventDefault() (which disable the default action when the button is clicked, e.g., submitting the form).
I haven't tested this out myself, but I guess it should work.
Background
I have a bootstrap modal that pop ups and display input forms, if the user makes changes and cancels/closes the modal a confirm box will identify they will lose changes.
The modal fires two events, hide when the modal begins closing and hidden when the modal is completely closed.
I'm intercepting the hide event with:
.on('hide',function(){
if(confirm('close'))
return true;
else
return false;
});
If I close the box and hit Ok, the modal will close.
If I hit cancel the modal will stay open (which is correct) but I will hit Ok after it will not continue the default event.
hit OK (works)
hit Cancel (works)
hit OK after hitting Cancel (fails)
I have tried preventDefault(); as well but I cannot figure out how to get the event to continue after a Cancel action.
Can be tested here:
http://jschr.github.io/bootstrap-modal/
Enter in console:
$('#responsive').on('hide', function() { if(confirm('close)) return true; else return false;});
What version of Bootstrap are you using?
Are you attaching the .on('hide') event to the modal element? For example:
$('.modal').on('hide', function(){...});
I tested your code in JS Fiddle (http://jsfiddle.net/5kbXZ/) using the example markup for a modal from Bootstrap 3 and it is working for me in Chrome Canary.
Diving into the source code of modal manager in bootstrap-modal.js line 84 of the hide function:
e && e.preventDefault();
e = $.Event('hide');
this.$element.trigger(e);
if (!this.isShown || e.isDefaultPrevented()) return (this.isShown = false); <--
this.isShown = false;
this.escape();
this.tab();
this.isShown is set to false causing a constant loop, it should be set to true since the modal isn't hidden when you fire e.preventDefault(). So the fix is:
if (!this.isShown || e.isDefaultPrevented()) return (this.isShown = true);
I'm using Telerik controls for my project. On my page, there are some links to another page, several radtextboxes and a radbutton (it causes a postback). When the textbox values are changed, the button becomes enabled. Then, in my window.onbeforeunload, I check if the button is enabled or disabled. If it is enabled, then the confirm dialog appears. The code looks like this :
window.onbeforeunload = function (evt) {
var ClientGeneral_btnSave = $find('<%=btnSave.ClientID %>');
if (ClientGeneral_btnSave.get_enabled() == true) {
var message = 'You will lose unsaved data?';
if (typeof evt == 'undefined') {
evt = window.event;
}
if (evt) {
evt.returnValue = message;
}
return message;
}
This code works well. When I close the tab, the confirm dialog appears. When I click on the links, it does. But, when I click on the btnSave itself, the dialog appears too, which is unsual. I want the btnSave NOT to cause onbeforeunload event
Please tell me how to do this.
Thank you in advance
It will fire onbeforeunload this if the btnSave posts back which it looks as if it is. Therefore you have a couple of choices
Prevent the btnSave from posting back if you don't need it to. Easiest way to do it is put this attribute in the asp:Button markup
OnClientClick="return false"
Wire up a javaScript/jQuery method to disable the onbeforeunload event. I did this before by stashing an value in a hidden field and using this to signal that the onbeforeunload event should fire.
for instance
$('#<%= btnSave.ClientID %>').bind('click', function(e){
$('#myHiddenFieldId').val('1');
});
and change your on beforeunload handler to check that the hidden field is not equal to 1 (make 0 the default i.e.
window.onbeforeunload = function (evt) {
if( $('#myHiddenFieldId').val() != '1')
{
//your logic here
}
}
You could probably do something better by unbinding the onbeforeunload handler in the btnSave click event using JQuery rather than using a hidden field to override.
Option 2 can get fiddly though - so best of luck
I'm creating a popup window that has a beforeunload handler installed. When the "Close" file menu item is used to close the popup, the beforeunload handler is called twice, resulting in two "Are you sure you want to close this window?" messages appearing.
This is a bug with Firefox, and I've reported it here, but I still would like a way to prevent this from happening. Can you think of a sane way of detecting double beforeunload to prevent the double message problem? The problem is that Firefox doesn't tell me which button in the dialog the user elected to click - OK or cancel.
<script type="text/javascript">
var onBeforeUnloadFired = false;
window.onbeforeunload = function ()
{
if (!onBeforeUnloadFired) {
onBeforeUnloadFired = true;
event.returnValue = "You have attempted to leave this page. If you have made any changes to the fields without clicking the Save button, your changes will be lost. Are you sure you want to exit this page?";
}
window.setTimeout("ResetOnBeforeUnloadFired()", 10);
}
function ResetOnBeforeUnloadFired() {
onBeforeUnloadFired = false;
}
</script>
Set a variable in the handler to prevent the dialog coming up the second time. Use setTimeout to reset it afterwards.
This is definitely a FF bug. I've reported it at https://bugzilla.mozilla.org/show_bug.cgi?id=531199
The best solution I've found is to use a flag global variable that is reset after so many milliseconds, say 500 (this ensures that the function can be called again, but not immediately after its appearance).
See last code in:
http://social.msdn.microsoft.com/Forums/en/sharepointinfopath/thread/13000cd8-5c50-4260-a0d2-bc404764966d
I've found this problem in Chrome 21, Firefox 14, IE 7-9, Safari 5 (on PC).
The following works on all of these browsers. If one removes the window.onbeforeunload function during the event this will prevent the second call. The trick is to reset the window.onbeforeunload function if the user decides to stay on the page.
var window_on_before_unload = function(e) {
var msg;
// Do here what you ever you need to do
msg = "Message for user";
// Prevent next "window.onbeforeunload" from re-running this code.
// Ensure that if the user decides to stay on the page that
// this code is run the next time the user tries to leave the page.
window.onbeforeunload = set_on_before_unload;
// Prepare message for user
if (msg) {
if (/irefox\/([4-9]|1\d+)/.test(navigator.userAgent))
alert(msg
+ '\n\nThe next dialog will allow you to stay here or continue\nSee Firefox bug #588292');
(e = e || window.event).returnValue = msg;
return msg;
}
};
// Set window.onbeforeunload to the above handler.
// #uses window_on_before_unload
// #param {Event} e
var set_on_before_unload = function(e) {
// Initialize the handler for window.onbeforeunload.
window.onbeforeunload = window_on_before_unload;
}
// Initialize the handler for window.onbeforeunload.
set_on_before_unload();
Create a global variable that is set to true inside the handler. Only show the alert/popup when this variable is false.
I use the following snippet to track the exitcount
When the page loads the following variable exitCount is initialized
if (typeof(MTG) == 'undefined') MTG = {};
MTG.exitCount=0;
and in the Window unload event
$(window).bind("beforeunload", function(){
if (MTG.exitCount<=0)
{
//do your thing, save etc
}
MTG.exitCount++;
});
I've found that instead of doing your own call to confirm(), just do even.preventDefault(); within the beforeunload event. Firefox throws up its own confirm dialog.
I'm not sure if this is the correct/standard thing to do, but that's how they're doing it.
I have a document opening another popup window with window.open. In the original window I have registered (with jquery) a listener for "unload" event like this:
var popup_window = window.open(...)
$(popup_window).on('unload', function(event) ...
I have came across this page because the event was effectively triggering twice. What I have found is that it is not a bug, it triggers twice because it fires once for "about:blank" page being replaced by your page and another for your page being unloaded.
All I have to do is to filter the event that I am interested in by querying the original event:
function (event) {
var original_url = e.originalEvent.originalTarget.URL;
if (original_url != 'about:blank')
{
... do cool things ...
}
}
I don't know if this applies to the original question, because it is a special case of a window opening another, but I hope it helps.