Do something before reload or close in vue.js - javascript

I have a Vue.JS application with a beforeDestroy method that I'm trying to use to store some data in local storage before the app closes or is reloaded.
Just for reference:
beforeDestroy: function() {
localStorage.setItem('preference', this.preference);
...
}
However, neither closing nor reloading the app actually calls this method.
How can I make sure this method is called before the app is closed?

What is it that "closes" or "reloads" the app? Is it the user in the browser closing the window and/or refreshing the page?
If that is the case, nothing is "destroyed" and that function won't run.
You would have to define a onbeforeunload function globally:
window.onbeforeunload = function(){
return "Are you sure you want to close the window?";
}
Then you can save items to local storage inside that function before the return statement.
Note: don't define it inside your beforeDestroy function, because again, that just won't run when you reload the page or navigate away.

Understand this question is quite old but if I'm out there searching for it, someone else is!
Unfortunately, as far I can tell there is nothing in Vue that can currently hook into before the user reloads the page either via closing, CMD+R, selecting a new URL etc.
The best solution, if it's sensitive data and you really want them to think about what they are doing, you can do the below which is taken from this medium post.
<script>
export default {
data: () => ({
isEditing: false
})
beforeMount() {
window.addEventListener("beforeunload", this.preventNav)
},
methods: {
preventNav(event) {
if (!this.isEditing) return
event.preventDefault()
event.returnValue = ""
}
}
}
</script>
This will at least bring up a dialogue box asking if they are really sure they want to reload the page.
Note the text of the dialogue box cannot be altered. A good description of what is going on with the dialogue box text is contained in this StackOverflow question.

Related

Angular - Pass info how an opend window was closed to the component from which the window was invoked

I am opening a new window (let's call it New Calculation) from a component that is not related to it (Calculation List).
const windowHandler: Window = window.open(appUrl);
const calculateSnackbarInterval = setInterval((): void => {
this.calculateOpened = true;
this.ref.detectChanges();
if (windowHandler.closed) {
this.snackBarService.openSnackBar({
type: 'info',
message: this.translate.instant(this.getTranslateKeyForSnackBar()),
actions: [
{
label: this.translate.instant(`snackbar.actions.abort`),
action: SnackbarAction.ABORT,
},
],
});
this.calculateOpened = false;
this.ref.detectChanges();
this.pullingIntervalDelete?.unsubscribe();
clearInterval(this.maximumPullingInterval);
this.startPullingInterval();
clearInterval(calculateSnackbarInterval);
}
}, 1000);
}
The invoked New Calculation window can be closed by "Cancel" button, using the browser, or pressing the "Calculate" button.
Currently a snackbar appears in Calculation List when closing the New Calculation, it doesn't matter which way was chosen. I would like to invoke this snackbar, only when the New Calculation window is closed using the "Calculate" button.
I have thought about 2 possible solutions:
Using local storage to save the information which button was used to close the window, and read it from the windowHandler.
Cons: Not sure about the security aspect, I would like to avoid the user tampering with it, and the user can edit local storage.
Build a dedicated service that reacts to an event assigned to "Calculate" button.
Cons: This one seems like an overkill for me with all of the listeners and dependencies.
Is there a preferred method to achieve this?
Thank you in advance.
I've came up with a simple solution. It's not the prettiest practice, however
it doesn't seem to be an overkill and user won't be able to tamper with it easily.
On the button triggering a new calculation I've added:
(this.window as any).calculationStarted = true;
and simply changed the receiver to
if (windowHandler.closed && (windowHandler as any).calculationStarted) {

How to Refresh (F5) and get another page with AngularJS?

In my web application, I got a form on 2 different pages, purchase1 and purchase2.
If a customer refreshes the page at purchase2, I want the location to be changed back to purchase1.
I haven't found a way to do so, I've tried to make a config like that:
.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.when('/purchase2', '/purchase1');
}
But obviously, that way I can never get to purchase2 page.
I need it to happen only on manual user Refresh.
Is there any way to do so? Some built-in Angular function that happens on Refresh?
Something like
$scope.onRefresh = function(){
$location.path('/dashboard/purchase1');
}
Haven't found anything like it.
You can listen for beforeunload event. beforeunload event will be triggered when someone hits a F5 or refreshes the page anyhow. Do something like,
var windowElement = angular.element($window);
windowElement.on('beforeunload', function (event) {
event.preventDefault();
//below is the redirect part.
$window.location.href = '/purchase1';
});
Put this code on purchase2 page.
Yes, you can do it.
Register a global listener for state change:
$scope.$on('$stateChangeStart', function(event, toState, toParams, fromState) {
// If fromState is null that means it is a page refresh otherwise
// The fromState will be the purchase1
if (toState.name == 'purchase2' && !fromState) {
$state.go('purchase1');
event.preventDefault();
return;
}
});
By global, I mean register the above in such a controller whose scope is available throughout your application like a controller added to your body or html tag.
Also, I'm assuming the purchase1 & purchase2 are the name of your states for both the pages. If they are parameters to a common state you can alter the code above.
What happens on refresh is the same as what happens on first load.
What you can do is check whether the user has been here already, e.g. by setting a cookie and reading it later.
However, I think you should rethink your design. Why would you invest your time into making refresh function behave worse?
I think, javascript isnt the right way because javascript does not know anything about the previous page, because it will be rendered when page is already loaded. So try to check this in your server side application like in php or jsp and read the request-header because there you can get current url and redirect user to the new url
You can try to have a flag say purchase2-loaded and keep this variable in localStorage. You can then write an IIFE, which will check value of this variable and reroute to purchase1.
Also on purchase1, reset it to false.
Note:This is a pure JS Code and relies on localStorage.
Fiddle.
Sample Code
(function(){
var isPurchase2Loaded = localStorage.getItem("Purchase2");
if(isPurchase2Loaded || isPurchase2Loaded === undefined){
document.write("Rerouting to purchase 1...");
}
else{
document.write("Loading for the first Time...");
localStorage.setItem("Purchase2", true);
}
})()
Eventually, if someone is interested, I fixed it like that:
In purchase1.js I've added this to the submit() function:
$rootscope.demographic=1;
In purchase2.js I've added this code to the controller:
var init = function(){
if(angular.isUndefined($rootScope.demographic)){
$location.path('/purchase1');
}
};
init();
It is working because Refresh(F5) completely restarting the application, therefore also resets the $rootscope and makes "Demographic" Undefined.
Upon entering purchase2, "init" function will start, if we came from purchase1 everything will be ok and demographic will be defined, otherwise we will just load purchase1 again.
:)
$state.go('purchase1');
this should resolve your problem.

How to extract target hostname during onbeforeunload event

I'd like to warn the user when he/she tries to navigate away from my webapp when his/her project is unsaved. Currently I don't care about edit boxes which are currently under edit. I know the project's dirty state from the session.
I quickly realized that if I set a function for the window.onbeforeunload, it'll disturb the user even if he/sh navigates to another page within my webapp. In such case no disturbance needed, the session will be still alive.
I tried a solution derived from Fire onbeforeunload only when window is closed (includes working example)
window.onbeforeunload = function (e) {
var targetHost = new URL(e.target.URL).hostname;
if (targetHost != window.location.host)
return "Project is unsaved!!!";
else
return null;
};
The new URL(e.target.URL).hostname results in (at least on IE11):
JavaScript runtime error: Object doesn't support this action
And mysteriously I can't find anything about no new URL(e.target.URL).hostname by any search.
But at the same time I hope this is not impossible, I cannot believe others didn't experience this.
There are two problems in your script:
window.onbeforeunload = function (e) {
var targetHost = new URL(e.target.URL).hostname;
if (targetHost != window.location.host) {
return "Project is unsaved!!!";
else
return null;
};
The first is that you did not close your if. The second is that e.target.URL is apparently not supported by IE. You need to have an A and a B plan.
A plan: Applies to the case when e.target.URL exists. In this case, you handle the case as you initially implemented, but with the syntax fix mentioned above.
B plan: Applies to the case when e.target.URL does not exist. For this case, you should assume that the user leaves the site. You can improve the approach by adding knowledge when the user uses your control to navigate, for instance, you know that a given anchor will stay on the site. In this case, you can define a click event and set a boolean value to true (and the default value of that boolean should be false...), so that later your onbeforeunload event will know that your user stayed on the site even if he or she uses IE.
So you need a logic like this:
var targetHost = !!e.target.URL ? (new URL(e.target.URL).hostname) : ((myFlag) ? (window.location.hostname) : ("elsewhere"));

Prompting user when form fields have changed and they do not save

Pretty common scenario here, a user changes fields in a form and leaves the page without saving. I throw a warning message.
I first began with using
$(window).bind("beforeunload", function(){ });
But I want to throw a Dialog and give the user some options, I opted for this instead.
$("#myForm").change( function(){
$("a:not(:#myForm a)").click( function(){
$("#promptDialog").dialog("open");
return false;
});
});
The only scenario in which this doesn't accurately work is when the user changes a field, then changes it back to it's original value (It shouldn't prompt, but does).
Is this solution elegant, is there a better way to do this?
I'm afraid the onbeforeunload-part is hard to replace, there are still other ways to leave a page than clicking a link, and you can't intercept all of them.
But the issue with the change-event can be handled a better way.
On DOMready store the initial values of the form somewhere, e.g. inside the form's data.
On beforeunload you may compare the stored values and the current values to determine if there have been any changes:
jQuery(
function($)
{
$('#myForm').data('defaultValues',$('#myForm').serialize());
$(window)
.on('beforeunload',
function()
{
if($('#myForm').data('defaultValues')!=$('#myForm').serialize())
{
return 'are you sure?';
}
});
}
);
You can't override the implementation features of the browser. You want to exchange the standard alert (an implementation-defined construct) for your custom dialog, which you can't do in the onbeforeunload function. Your latter solution should suffice as a substitute.

jQuery, onBeforeUnload and ASP.Net form

I have the following solution for stopping the users from accidentally leaving my registration page:
var warning = true;
function CheckExit() {
if (warning) {
return "Changes done. Remember to save, blah blah.";
}
}
window.onbeforeunload = CheckExit;
addToPostBack = function (func) {
var old__doPostBack = __doPostBack;
if (typeof __doPostBack != 'function') {
__doPostBack = func;
} else {
__doPostBack = function (t, a) {
if (func(t, a)) old__doPostBack(t, a);
}
}
};
$(document).ready(function () {
$('#aspnetForm').submit(function () {
warning = false;
return true;
});
addToPostBack(function (t, a) {
warning = false;
return true;
});
});
Most of this code is from different questions here on StackOverflow, and works just fine on my local debugging page; all ASP.Net controls (linkbuttons, buttons) can be clicked without a warning, but as soon as the user tries to close the window or navigate away, the warning is displayed.
However, when deployed to my server, the warning pops up when I click ASP.Net controls too (and I really do not want to warn the user that his changes isn't saved when he clicks the "Save" button). Now, there is a difference between my local debugging page and the server: the server uses a different MasterPage with some ads in it, but after debugging with Firebug (see next paragraph), I can't see how that should make a difference.
I have tried running different parts of the Javascript code by using Firebug to confirm that everything is loaded correctly (my first guess was that the section containing $('#aspnetForm') wasn't being loaded, since this seems to be the difference), but there is no improvement at all. The warning still pops up on every click of a link or a button.
My main problem is, I think, that I do not fully understand what the addToPostBack function does, and as such, I cannot properly debug it.
Is there anybody here who has any idea what might be wrong?
It's a guess, but you don't have the conventional anti-conflict device which goes
(function ($) { code here })(jQuery);
so something might be conflicting with jQuery's definition of '$' which would stop the execution of the exception your code makes when someone is posting back.
I agree with James. Most of the time such type of conflict occurs. I will suggest with noConflict().
Happy Coding.

Categories

Resources