I have an app written in Ionic v1 and AngularJS.
The app is using $ionicPlatform.registerBackButtonAction to handle the device's back button action.
Everything is working great when normally using the app. The problem is starting when the app is being opened by a push notification.
When the app is not in the background, and is being opened by clicking the push notification, the back button handler is not being registered and the physical back button throws me out of the app.
If I click anywhere on the screen (click, not scroll) then the touch event is being registered and everything is working well.
I have tried registering the event in multiple locations after the push notification event is launched.
I have tried simulating a touch event programaticlly on an empty space on the screen.
I have tried dispatching the resume event to simulate a return from paused state.
I have tried reloading the page programmaticlly after page loads.
Nothing seems to work.
The is my $ionicPlatform.registerBackButtonAction event handler that is being registered in app.run:
$ionicPlatform.registerBackButtonAction(function(e) {
e.preventDefault();
function showConfirm() {
var confirmPopup = $ionicPopup.show({
title : 'Close',
template : '<div>Do you want to close the app?</div>',
buttons : [
{
text : '<b>Cancel</b>'
},
{
text : '<b>Approve</b>',
type: 'button-positive',
onTap : function() {
ionic.Platform.exitApp();
}
}
]
});
};
// Is there a page to go back to?
if ($ionicHistory.backView()) {
// Go back in history
if($rootScope.pushPressed2) {
$location.path('/app/home').replace();
}
else {
$rootScope.backButtonPressed = true;
$ionicHistory.backView().go();
}
}
else {
if($rootScope.pushPressed2) {
$location.path('/app/home').replace();
}
else {
showConfirm();
}
}
return false;
}, 101);
$ionicPlatform.registerBackButtonAction(function(event)
{
if ($ionicHistory.currentStateName() === "home" )
{
$cordovaDialogs.confirm('Are You Sure You Want to Exit?', 'AppName', ['Cancel','OK'])
.then(function(buttonIndex) {
// no button = 0 'OK' = 1 'Cancel' = 2
var btnIndex = buttonIndex;
if(buttonIndex==2)
{
ionic.Platform.exitApp();
}
});
}
else
{
if($ionicHistory.currentStateName() === "login" )
{
ionic.Platform.exitApp();
}
else
{
$ionicHistory.goBack();
}
}
}, 100);
So currently in my windows 8 javascript app (based on the navigation template), upon navigation to the home page on app startup (home.html) from the default.js initialization point, in home.html's corresponding home.js file, I'm creating this gesture system to handle pinch to zoom and swiping back and forth (which works correctly):
(function () {
"use strict";
WinJS.UI.Pages.define("/pages/home/home.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
processed: function (element, options) {
MyGlobals.loadBooks();
if (!MyGlobals.localSettings.values['firstRunCompleted']) {
MyGlobals.localSettings.values['firstRunCompleted'] = true;
MyGlobals.loadXmlBooksIntoDatabase();
//MyGlobals.integrityCheck();
};
WinJS.Resources.processAll();
},
ready: function (element, options) {
var myGesture = new MSGesture();
var chapterContainer = document.getElementById("main-content-area");
myGesture.target = chapterContainer;
WinJS.Namespace.define("MyGlobals", {
myGesture: myGesture,
});
chapterContainer.addEventListener("MSGestureStart", this.gestureListener, false);
chapterContainer.addEventListener("MSGestureEnd", this.gestureListener, false);
chapterContainer.addEventListener("MSGestureChange", this.gestureListener, false);
chapterContainer.addEventListener("MSInertiaStart", this.gestureListener, false);
chapterContainer.addEventListener("MSGestureTap", this.gestureListener, false);
chapterContainer.addEventListener("MSGestureHold", this.gestureListener, false);
chapterContainer.addEventListener("pointerdown", this.gestureListener, false);
},
gestureListener: function (evt) {
console.log("in gesturelistener now");
if (evt.type == "pointerdown") {
MyGlobals.myGesture.addPointer(evt.pointerId);
return;
}
if (evt.type == "MSGestureStart") {
if (evt.translationX < -3.5) {
MyGlobals.nextChapterHandler();
};
if (evt.translationX > 3.5) {
MyGlobals.previousChapterHandler();
}
};
if (evt.type == "MSGestureChange") {
if (evt.scale < 1) {
MyGlobals.fontSizeModify("decrease");
};
if (evt.scale > 1) {
MyGlobals.fontSizeModify("increase");
}
};
},
The problem though is that when I navigate to another page using WinJS.Navigation.navigate(), when I then navigate back to home.html using WinJS.Navigation.navigate(), all of the above event listeners don't work, and seem to not be added to the chapterContainer (from inspecting the live DOM). However, all other event listeners that are in the ready: function, do work perfectly (other listeners omitted from above code). Is there something wrong that I'm doing here?
Thanks a lot!
The page being navigated to also had a div with id "main-content-area", and the event listeners were going onto the old page instead of the page being navigated back to.
I want to capture the browser window/tab close event.
I have tried the following with jQuery:
jQuery(window).bind(
"beforeunload",
function() {
return confirm("Do you really want to close?")
}
)
But it works on form submission as well, which is not what I want. I want an event that triggers only when the user closes the window.
The beforeunload event fires whenever the user leaves your page for any reason.
For example, it will be fired if the user submits a form, clicks a link, closes the window (or tab), or goes to a new page using the address bar, search box, or a bookmark.
You could exclude form submissions and hyperlinks (except from other frames) with the following code:
var inFormOrLink;
$('a').on('click', function() { inFormOrLink = true; });
$('form').on('submit', function() { inFormOrLink = true; });
$(window).on("beforeunload", function() {
return inFormOrLink ? "Do you really want to close?" : null;
})
For jQuery versions older than 1.7, try this:
var inFormOrLink;
$('a').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });
$(window).bind("beforeunload", function() {
return inFormOrLink ? "Do you really want to close?" : null;
})
The live method doesn't work with the submit event, so if you add a new form, you'll need to bind the handler to it as well.
Note that if a different event handler cancels the submit or navigation, you will lose the confirmation prompt if the window is actually closed later. You could fix that by recording the time in the submit and click events, and checking if the beforeunload happens more than a couple of seconds later.
Maybe just unbind the beforeunload event handler within the form's submit event handler:
jQuery('form').submit(function() {
jQuery(window).unbind("beforeunload");
...
});
For a cross-browser solution (tested in Chrome 21, IE9, FF15), consider using the following code, which is a slightly tweaked version of Slaks' code:
var inFormOrLink;
$('a').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });
$(window).bind('beforeunload', function(eventObject) {
var returnValue = undefined;
if (! inFormOrLink) {
returnValue = "Do you really want to close?";
}
eventObject.returnValue = returnValue;
return returnValue;
});
Note that since Firefox 4, the message "Do you really want to close?" is not displayed. FF just displays a generic message. See note in https://developer.mozilla.org/en-US/docs/DOM/window.onbeforeunload
window.onbeforeunload = function () {
return "Do you really want to close?";
};
My answer is aimed at providing simple benchmarks.
HOW TO
See #SLaks answer.
$(window).on("beforeunload", function() {
return inFormOrLink ? "Do you really want to close?" : null;
})
How long does the browser take to finally shut your page down?
Whenever an user closes the page (x button or CTRL + W), the browser executes the given beforeunload code, but not indefinitely. The only exception is the confirmation box (return 'Do you really want to close?) which will wait until for the user's response.
Chrome: 2 seconds.
Firefox: ∞ (or double click, or force on close)
Edge: ∞ (or double click)
Explorer 11: 0 seconds.
Safari: TODO
What we used to test this out:
A Node.js Express server with requests log
The following short HTML file
What it does is to send as many requests as it can before the browser shut downs its page (synchronously).
<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
function request() {
return $.ajax({
type: "GET",
url: "http://localhost:3030/" + Date.now(),
async: true
}).responseText;
}
window.onbeforeunload = () => {
while (true) {
request();
}
return null;
}
</script>
</body>
</html>
Chrome output:
GET /1480451321041 404 0.389 ms - 32
GET /1480451321052 404 0.219 ms - 32
...
GET /hello/1480451322998 404 0.328 ms - 32
1957ms ≈ 2 seconds // we assume it's 2 seconds since requests can take few milliseconds to be sent.
For a solution that worked well with third party controls like Telerik (ex.: RadComboBox) and DevExpress that use the Anchor tags for various reasons, consider using the following code, which is a slightly tweaked version of desm's code with a better selector for self targeting anchor tags:
var inFormOrLink;
$('a[href]:not([target]), a[href][target=_self]').live('click', function() { inFormOrLink = true; });
$('form').bind('submit', function() { inFormOrLink = true; });
$(window).bind('beforeunload', function(eventObject) {
var returnValue = undefined;
if (! inFormOrLink) {
returnValue = "Do you really want to close?";
}
eventObject.returnValue = returnValue;
return returnValue;
});
I used Slaks answer but that wasn't working as is, since the onbeforeunload returnValue is parsed as a string and then displayed in the confirmations box of the browser. So the value true was displayed, like "true".
Just using return worked.
Here is my code
var preventUnloadPrompt;
var messageBeforeUnload = "my message here - Are you sure you want to leave this page?";
//var redirectAfterPrompt = "http://www.google.co.in";
$('a').live('click', function() { preventUnloadPrompt = true; });
$('form').live('submit', function() { preventUnloadPrompt = true; });
$(window).bind("beforeunload", function(e) {
var rval;
if(preventUnloadPrompt) {
return;
} else {
//location.replace(redirectAfterPrompt);
return messageBeforeUnload;
}
return rval;
})
Perhaps you could handle OnSubmit and set a flag that you later check in your OnBeforeUnload handler.
Unfortunately, whether it is a reload, new page redirect, or browser close the event will be triggered. An alternative is catch the id triggering the event and if it is form dont trigger any function and if it is not the id of the form then do what you want to do when the page closes. I am not sure if that is also possible directly and is tedious.
You can do some small things before the customer closes the tab. javascript detect browser close tab/close browser but if your list of actions are big and the tab closes before it is finished you are helpless. You can try it but with my experience donot depend on it.
window.addEventListener("beforeunload", function (e) {
var confirmationMessage = "\o/";
/* Do you small action code here */
(e || window.event).returnValue = confirmationMessage; //Gecko + IE
return confirmationMessage; //Webkit, Safari, Chrome
});
https://developer.mozilla.org/en-US/docs/Web/Reference/Events/beforeunload?redirectlocale=en-US&redirectslug=DOM/Mozilla_event_reference/beforeunload
jQuery(window).bind("beforeunload", function (e) {
var activeElementTagName = e.target.activeElement.tagName;
if (activeElementTagName != "A" && activeElementTagName != "INPUT") {
return "Do you really want to close?";
}
})
If your form submission takes them to another page (as I assume it does, hence the triggering of beforeunload), you could try to change your form submission to an ajax call. This way, they won't leave your page when they submit the form and you can use your beforeunload binding code as you wish.
As of jQuery 1.7, the .live() method is deprecated. Use .on() to attach event handlers. Users of older versions of jQuery should use .delegate() in preference to .live()
$(window).bind("beforeunload", function() {
return true || confirm("Do you really want to close?");
});
on complete or link
$(window).unbind();
Try this also
window.onbeforeunload = function ()
{
if (pasteEditorChange) {
var btn = confirm('Do You Want to Save the Changess?');
if(btn === true ){
SavetoEdit();//your function call
}
else{
windowClose();//your function call
}
} else {
windowClose();//your function call
}
};
My Issue: The 'onbeforeunload' event would only be triggered if there were odd number of submits(clicks). I had a combination of solutions from similar threads in SO to have my solution work. well my code will speak.
<!--The definition of event and initializing the trigger flag--->
$(document).ready(function() {
updatefgallowPrompt(true);
window.onbeforeunload = WarnUser;
}
function WarnUser() {
var allowPrompt = getfgallowPrompt();
if(allowPrompt) {
saveIndexedDataAlert();
return null;
} else {
updatefgallowPrompt(true);
event.stopPropagation
}
}
<!--The method responsible for deciding weather the unload event is triggered from submit or not--->
function saveIndexedDataAlert() {
var allowPrompt = getfgallowPrompt();
var lenIndexedDocs = parseInt($('#sortable3 > li').size()) + parseInt($('#sortable3 > ul').size());
if(allowPrompt && $.trim(lenIndexedDocs) > 0) {
event.returnValue = "Your message";
} else {
event.returnValue = " ";
updatefgallowPrompt(true);
}
}
<!---Function responsible to reset the trigger flag---->
$(document).click(function(event) {
$('a').live('click', function() { updatefgallowPrompt(false); });
});
<!--getter and setter for the flag---->
function updatefgallowPrompt (allowPrompt){ //exit msg dfds
$('body').data('allowPrompt', allowPrompt);
}
function getfgallowPrompt(){
return $('body').data('allowPrompt');
}
Just verify...
function wopen_close(){
var w = window.open($url, '_blank', 'width=600, height=400, scrollbars=no, status=no, resizable=no, screenx=0, screeny=0');
w.onunload = function(){
if (window.closed) {
alert("window closed");
}else{
alert("just refreshed");
}
}
}
var validNavigation = false;
jQuery(document).ready(function () {
wireUpEvents();
});
function endSession() {
// Browser or broswer tab is closed
// Do sth here ...
alert("bye");
}
function wireUpEvents() {
/*
* For a list of events that triggers onbeforeunload on IE
* check http://msdn.microsoft.com/en-us/library/ms536907(VS.85).aspx
*/
window.onbeforeunload = function () {
debugger
if (!validNavigation) {
endSession();
}
}
// Attach the event keypress to exclude the F5 refresh
$(document).bind('keypress', function (e) {
debugger
if (e.keyCode == 116) {
validNavigation = true;
}
});
// Attach the event click for all links in the page
$("a").bind("click", function () {
debugger
validNavigation = true;
});
// Attach the event submit for all forms in the page
$("form").bind("submit", function () {
debugger
validNavigation = true;
});
// Attach the event click for all inputs in the page
$("input[type=submit]").bind("click", function () {
debugger
validNavigation = true;
});
}`enter code here`
Following worked for me;
$(window).unload(function(event) {
if(event.clientY < 0) {
//do whatever you want when closing the window..
}
});
I am using below code for detecting browser close event and then invalidate session. It works fine if directly I click on browser close button. If I click on some <a href > in the page then window.onbeforeunload is getting triggered and session gets invalidated.
Please let me know If some body knows the solution for this problem.
/*JS code begins here*/
/*Global js variable to decide whether to call session invalidate function*/
var validNavigation = false;
//Called when page loads initially
jQuery(document).ready(function() {
//Call to wireupEvents
wireUpEvents();
});
//Function called when the page loads
function wireUpEvents() {
window.onbeforeunload= function() {
if (!validNavigation) {
/*This JS function calls my managed bean method to invalidate session.*/
windowCloseJsFunction();
}
}
// Attach the event keypress to exclude the F5 refresh
jQuery(document).bind('keypress', function(e) {
if (e.keyCode == 116) {
alert('116');
validNavigation = true;
}
});
// Attach the event click for all links in the page
jQuery("a").bind("click", function() {
alert('click a');
validNavigation = true;
});
// Attach the event submit for all forms in the page
jQuery("form").bind("submit", function() {
alert('form');
validNavigation = true;
});
// Attach the event click for all inputs in the page
jQuery("input[type=submit]").bind("click", function() {
alert('input');
validNavigation = true;
});
//Attach button click for all inputs in the page
jQuery("input[type=button]").bind("click", function() {
validNavigation = true;
});
}
/*JS code ends here*/
I'm not sure this is a Meteor.js specific question, but here goes:
I've created a demo at http://numbersdemo.meteor.com/. If you try the demo in a desktop browser (I've only tried it in Chrome on Mac) it runs fine, the input from the buttons is instantly displayed in the results-thing. But if you try it on an iPhone, it's not quite as instant. And that's what I need!
Is it possible?
Is it a Meteor.js problem or just javascript/HTML in mobile Safari?
Below is all the .js for the app. And as you can see there are no DB connections at all going on, just a Session, so the DB is not the problem.
if (Meteor.isClient) {
Meteor.startup(function () {
Session.set('buttonsResult', 0);
});
Template.numbersThing.result = function () {
return Session.get('buttonsResult');
};
Template.numbersThing.events({
'mousedown .button' : function (event) {
var prevInput = Session.get('buttonsResult'),
newInput = prevInput + '' + $(event.currentTarget).text();
Session.set('buttonsResult', newInput);
},
'mousedown .reset' : function () {
Session.set('buttonsResult', 0);
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
});
}
Have you tried using an event like touchstart instead of mousedown?
Try using FastClick, which removes the 300ms delay time when tapping a link.