Unique jQuery popup issue - javascript

So I have to have a popup form display once per user session, the client wants it to popup after 10 seconds. If the user navigates to another page on the site, the form still needs to popup and not display after the user closes it on any other part of the site. Here is the jQuery I have written so far.
$(document).ready(function() {
sessionStorage.setItem('firstVisit', '1');
if (sessionStorage.getItem('firstVisit') === "1") {
setTimeout(function() {
$('.verif').fadeIn('fast');
}, 1000);
} else {
$('.verif').hide();
}
});
I have the form on each page and right now it just pops up all the time. Am I using the wrong method for the situation? All suggestions are welcome.

Note that the line 2 always sets firstVisit as '1' in session storage. This way, the expression for if will always be true and thus, user will always see the popup.
You need to get the item first, and check its value. Then if it doesn't exist, set it.
$(document).ready(function() {
var item = sessionStorage.getItem('firstVisit');
if (!item || item !== "1") {
setTimeout(function() {
$('.verif').fadeIn('fast');
}, 1000);
sessionStorage.setItem('firstVisit', '1');
} else {
$('.verif').hide();
}
});
Also, using sessionStorage is not a good idea as it is volatile across page refreshes. You, instead, may want to use localStorage for this as you mentioned that this needs to be done for any page.

Related

How do I ask the user to confirm they want to leave the page?

I have a web site that contains several pages where the user can add and edit information. In order to provide a consistent UI, I have the following JavaScript function...
function setWindowBeforeUnload(changed) {
$(window).on("beforeunload", function() {
if (confirmLeave && changed && changed()) {
return "You haven't saved the information. If you leave this page, the information will be lost.";
}
});
}
confirmLeave is a global variable that specifies if we are to ask them for confirmation before navigating away (which we don't if we are navigating to another page after a successful save). changed is a function that checks if the entity has changed.
This is called from a details page (say the customer page) as follows...
$(document).ready(function() {
setWindowBeforeUnload(customerChanged);
});
function customerChanged() {
// Checks the data and returns true or false as appropriate
}
This all worked fine until recently, when a change in Chrome broke it.
I have searched for hours, and found loads of people suggesting code like this...
addEventListener('beforeunload', function(event) {
event.returnValue = 'You have unsaved changes.';
});
...which works fine as it is, except that it fires the warning whenever they leave the page, irrespective of whether or not the data has changed.
As soon as I try to add any logic (such as my checking code in the first sample), it doesn't work...
function setWindowBeforeUnload(changed) {
addEventListener('beforeunload', function(event) {
if (confirmLeave && changed && changed()) {
event.returnValue = 'You have unsaved changes.';
}
});
}
With this code, I can navigate away from the page without getting a warning.
Is there any way to reproduce my original behaviour now?
You can use logic in the handler, you just can't have a custom message any more.
See the code below. Use the "Run code snippet" to simulate navigation. Run the snippet, run it again no confirm. Toggle the button to "false" run the snippet and get a confirm.
var test = true;
function otherTest() {
return true;
}
addEventListener('beforeunload', function(event) {
if(!test || !otherTest()) {
event.returnValue = 'You have unsaved changes.';
}
});
document.getElementById('theButton').addEventListener('click', function(event) {
test = !test;
this.innerHTML = test.toString();
});
<p>Click the button to turn the confirm on and off</p>
<button id="theButton">true</button>

How to know if there is a previous page [duplicate]

I want using JavaScript to see if there is history or not, I mean if the back button is available on the browser or not.
Short answer: You can't.
Technically there is an accurate way, which would be checking the property:
history.previous
However, it won't work. The problem with this is that in most browsers this is considered a security violation and usually just returns undefined.
history.length
Is a property that others have suggested...
However, the length doesn't work completely because it doesn't indicate where in the history you are. Additionally, it doesn't always start at the same number. A browser not set to have a landing page, for example, starts at 0 while another browser that uses a landing page will start at 1.
Most of the time a link is added that calls:
history.back();
or
history.go(-1);
and it's just expected that if you can't go back then clicking the link does nothing.
There is another way to check - check the referrer. The first page usually will have an empty referrer...
if (document.referrer == "") {
window.close()
} else {
history.back()
}
My code let the browser go back one page, and if that fails it loads a fallback url. It also detect hashtags changes.
When the back button wasn't available, the fallback url will be loaded after 500 ms, so the browser has time enough to load the previous page. Loading the fallback url right after window.history.go(-1); would cause the browser to use the fallback url, because the js script didn't stop yet.
function historyBackWFallback(fallbackUrl) {
fallbackUrl = fallbackUrl || '/';
var prevPage = window.location.href;
window.history.go(-1);
setTimeout(function(){
if (window.location.href == prevPage) {
window.location.href = fallbackUrl;
}
}, 500);
}
Here is how i did it.
I used the 'beforeunload' event to set a boolean. Then I set a timeout to watch if the 'beforeunload' fired.
var $window = $(window),
$trigger = $('.select_your_link'),
fallback = 'your_fallback_url';
hasHistory = false;
$window.on('beforeunload', function(){
hasHistory = true;
});
$trigger.on('click', function(){
window.history.go(-1);
setTimeout(function(){
if (!hasHistory){
window.location.href = fallback;
}
}, 200);
return false;
});
Seems to work in major browsers (tested FF, Chrome, IE11 so far).
There is a snippet I use in my projects:
function back(url) {
if (history.length > 2) {
// if history is not empty, go back:
window.History.back();
} else if (url) {
// go to specified fallback url:
window.History.replaceState(null, null, url);
} else {
// go home:
window.History.replaceState(null, null, '/');
}
}
FYI: I use History.js to manage browser history.
Why to compare history.length to number 2?
Because Chrome's startpage is counted as first item in the browser's history.
There are few possibilities of history.length and user's behaviour:
User opens new empty tab in the browser and then runs a page. history.length = 2 and we want to disable back() in this case, because user will go to empty tab.
User opens the page in new tab by clicking a link somewhere before. history.length = 1 and again we want to disable back() method.
And finally, user lands at current page after reloading few pages. history.length > 2 and now back() can be enabled.
Note: I omit case when user lands at current page after clicking link from external website without target="_blank".
Note 2: document.referrer is empty when you open website by typing its address and also when website uses ajax to load subpages, so I discontinued checking this value in the first case.
this seems to do the trick:
function goBackOrClose() {
window.history.back();
window.close();
//or if you are not interested in closing the window, do something else here
//e.g.
theBrowserCantGoBack();
}
Call history.back() and then window.close(). If the browser is able to go back in history it won't be able to get to the next statement. If it's not able to go back, it'll close the window.
However, please note that if the page has been reached by typing a url, then firefox wont allow the script to close the window.
Be careful with window.history.length because it also includes entries for window.history.forward()
So you may have maybe window.history.length with more than 1 entries, but no history back entries.
This means that nothing happens if you fire window.history.back()
You can't directly check whether the back button is usable. You can look at history.length>0, but that will hold true if there are pages ahead of the current page as well. You can only be sure that the back button is unusable when history.length===0.
If that's not good enough, about all you can do is call history.back() and, if your page is still loaded afterwards, the back button is unavailable! Of course that means if the back button is available, you've just navigated away from the page. You aren't allowed to cancel the navigation in onunload, so about all you can do to stop the back actually happening is to return something from onbeforeunload, which will result in a big annoying prompt appearing. It's not worth it.
In fact it's normally a Really Bad Idea to be doing anything with the history. History navigation is for browser chrome, not web pages. Adding “go back” links typically causes more user confusion than it's worth.
history.length is useless as it does not show if user can go back in history.
Also different browsers uses initial values 0 or 1 - it depends on browser.
The working solution is to use $(window).on('beforeunload' event, but I'm not sure that it will work if page is loaded via ajax and uses pushState to change window history.
So I've used next solution:
var currentUrl = window.location.href;
window.history.back();
setTimeout(function(){
// if location was not changed in 100 ms, then there is no history back
if(currentUrl === window.location.href){
// redirect to site root
window.location.href = '/';
}
}, 100);
Building on the answer here and here. I think, the more conclusive answer is just to check if this is a new page in a new tab.
If the history of the page is more than one, then we can go back to the page previous to the current page. If not, the tab is a newly opened tab and we need to create a new tab.
Differently, to the answers linked, we are not checking for a referrer as a new tab will still have a referrer.
if(1 < history.length) {
history.back();
}
else {
window.close();
}
This work for me using react but can work in another case; when history is in the first page (you cannot go back) window.history.state will be null, so if you want to know if you can navigate back you only need:
if (window.history.state == null) {
//you cannot go back
}
Documentation:
The History.state property returns a value representing the state at
the top of the history stack. This is a way to look at the state
without having to wait for a popstate event.
I was trying to find a solution and this is the best i could get (but works great and it's the easiest solution i've found even here).
In my case, i wanted to go back on history with an back button, but if the first page the user opened was an subpage of my app, it would go back to the main page.
The solution was, as soon the app is loaded, i just did an replace on the history state:
history.replaceState( {root: true}, '', window.location.pathname + window.location.hash)
This way, i just need to check history.state.root before go back. If true, i make an history replace instead:
if(history.state && history.state.root)
history.replaceState( {root: true}, '', '/')
else
history.back()
I came up with the following approach. It utilizes the onbeforeunload event to detect whether the browser starts leaving the page or not. If it does not in a certain timespan it'll just redirect to the fallback.
var goBack = function goBack(fallback){
var useFallback = true;
window.addEventListener("beforeunload", function(){
useFallback = false;
});
window.history.back();
setTimeout(function(){
if (useFallback){ window.location.href = fallback; }
}, 100);
}
You can call this function using goBack("fallback.example.org").
There is another near perfect solution, taken from another SO answer:
if( (1 < history.length) && document.referrer ) {
history.back();
}
else {
// If you can't go back in history, you could perhaps close the window ?
window.close();
}
Someone reported that it does not work when using target="_blank" but it seems to work for me on Chrome.
the browser has back and forward button. I come up a solution on this question. but It will affect browser forward action and cause bug with some browsers.
It works like that: If the browser open a new url, that has never opened, the history.length will be grow.
so you can change hash like
location.href = '#__transfer__' + new Date().getTime()
to get a never shown url, then history.length will get the true length.
var realHistoryLength = history.length - 1
but, It not always work well, and I don't known why ,especially the when url auto jump quickly.
I am using window.history in Angular for the FAQ on my site.
Whenever the user wants to exit the FAQ they can click the exit button (next to the back button)
My logic for this "exit" strategy is based on the entry ID and then just go back the number of states till that state.
So on enter:
enterState: { navigationId:number } = {navigationId: 1}
constructor() {
this.enterState = window.history.state
}
pretent the user navigates through the faq
And then, when the user clicks the exit button, read the current state and calculate your delta:
exitFaq() {
// when user started in faq, go back to first state, replace it with home and navigate
if (this.enterState.navigationId === 1) {
window.history.go((window.history.state.navigationId - 1) * -1)
this.router.navigateByUrl('/')
// non-angular
// const obj = {Title: 'Home', Url: '/'}
// window.history.replaceState(obj, obj.Title, obj.Url)
} else {
window.history.go(this.enterState.navigationId - window.history.state.navigationId - 1)
}
}
As you can see, I also use a fallback for when the user started in the faq, in that case the state.navigationId is 1 and we want to route back, replace the first state and show the homepage (For this I'm using the Angular router, but you can use history.replaceState as well when you handle your own routes)
For reference:
history.go
history.state
history.replaceState
Angular.router.navigateByUrl
This might help:
const prev = window.location.pathname;
window.history.back();
setTimeout(() => {
if (prev === window.location.pathname) {
// Do something else ...
}
}, 1000);
I'm using Angular, I need to check if there is history, trigger location.back(), else redirect to parent route.
Solution from https://stackoverflow.com/a/69572533/18856708 works well.
constructor(
private activatedRoute: ActivatedRoute,
private router: Router,
private location: Location,
}
...
back(): void {
if (window.history.state === null) {
this.router.navigate(['../'], { relativeTo: this.activatedRoute });
return;
}
this.location.back();
}
This is my solution:
function historyBack() {
console.log('back');
window.history.back() || window.history.go(-1);
if (!window.history.length) window.close();
var currentUrl = window.location.href;
setTimeout(function(){
// if location was not changed in 100 ms, then there is no history back
if(current === window.location.href){
console.log('History back is empty!');
}
}, 100);
}
function historyForward() {
console.log('forward');
window.history.forward() || window.history.go(+1);
var current = window.location.href;
setTimeout(function(){
// if location was not changed in 100 ms, then there is no history forward
if(current === window.location.href){
console.log('History forward is empty!');
}
}, 100);
}
The following solution will navigate back AND will tell if the navigation occurred or not:
async function goBack() {
return new Promise((resolve, reject) => {
const timer = setTimeout(() => reject('nowhere to go'), 100);
window.history.back();
const onBack = () => {
window.removeEventListener('beforeunload', onBack);
window.removeEventListener('popstate', onBack);
clearTimeout(timer);
resolve(true);
};
window.addEventListener('beforeunload', onBack);
window.addEventListener('popstate', onBack);
});
}
// usage
await goBack().catch(err => console.log('failed'));
How it works:
Try to navigate back
Add event listeners that will trigger on navigation to another website or to another page on the same site (SPA website, etc.)
If above events didn't occur in 100ms, deduce that there's nowhere to go back to
Notice that goBack() is an async function.
var fallbackUrl = "home.php";
if(history.back() === undefined)
window.location.href = fallbackUrl;
I am using a bit of PHP to achieve the result. It's a bit rusty though. But it should work.
<?php
function pref(){
return (isset($_SERVER['HTTP_REFERER'])) ? true : '';
}
?>
<html>
<body>
<input type="hidden" id="_pref" value="<?=pref()?>">
<button type="button" id="myButton">GoBack</button>
<!-- Include jquery library -->
<script>
if (!$('#_pref').val()) {
$('#myButton').hide() // or $('#myButton').remove()
}
</script>
</body>
</html>
var func = function(){ console.log("do something"); };
if(document.referrer.includes(window.location.hostname) && history.length-1 <= 1){
func();
}
else{
const currentUrl = window.location.href;
history.back();
setTimeout(function(){
currentUrl === window.location.href && func();
}, 100);
}
I found a JQuery solution that actually works
window.history.length == 1
This works on Chrome, Firefox, and Edge.
You can use the following piece of JQuery code that worked for me on the latest versions of all of the above 3 browsers if you want to hide or remove a back button on your developed web page when there is no window history.
$(window).load(function() {
if (window.history.length == 1) {
$("#back-button").remove();
}
})
Solution
'use strict';
function previousPage() {
if (window.location.pathname.split('/').filter(({ length }) => length > 0).length > 0) {
window.history.back();
}
}
Explaination
window.location.pathname will give you the current URI. For instance https://domain/question/1234/i-have-a-problem will give /question/1234/i-have-a-problem. See the documentation about window.location for more informations.
Next, the call to split() will give us all fragments of that URI. so if we take our previous URI, we will have something like ["", "question", "1234", "i-have-a-problem"]. See the documentation about String.prototype.split() for more informations.
The call to filter() is here to filter out the empty string generated by the backward slash. It will basically return only the fragment URI that have a length greater than 1 (non-empty string). So we would have something like ["question", "1234", "i-have-a-question"]. This could have been writen like so:
'use strict';
window.location.pathname.split('/').filter(function(fragment) {
return fragment.length > 0;
});
See the documentation about Array.prototype.filter() and the Destructuring assignment for more informations.
Now, if the user tries to go back while being on https://domain/, we wont trigger the if-statement, and so wont trigger the window.history.back() method so the user will stay in our website. This URL will be equivalent to [] which has a length of 0, and 0 > 0 is false. Hence, silently failing. Of course, you can log something or have another action if you want.
'use strict';
function previousPage() {
if (window.location.pathname.split('/').filter(({ length }) => length > 0).length > 0) {
window.history.back();
} else {
alert('You cannot go back any further...');
}
}
Limitations
Of course, this solution wont work if the browser do not support the History API. Check the documentation to know more about it before using this solution.
I'm not sure if this works and it is completely untested, but try this:
<script type="text/javascript">
function goBack() {
history.back();
}
if (history.length > 0) { //if there is a history...
document.getElementsByTagName('button')[].onclick="goBack()"; //assign function "goBack()" to all buttons onClick
} else {
die();
}
</script>
And somewhere in HTML:
<button value="Button1"> //These buttons have no action
<button value="Button2">
EDIT:
What you can also do is to research what browsers support the back function (I think they all do) and use the standard JavaScript browser detection object found, and described thoroughly, on this page. Then you can have 2 different pages: one for the "good browsers" compatible with the back button and one for the "bad browsers" telling them to go update their browser
Check if window.history.length is equal to 0.

react history replace disallow back button

I know it's impossible technically to disable user to click the back button of the browser, but it doesn't make sense some time in our app we allow that kind of operation.
For example in my job application app, after you apply you go to next page,
this.props.applyJob({
id: this.state.selectedAd_Id,
applicant_id
}).then(response => {
if(response.value.status === 200){
const { id } = response.value.data.result
this.props.history.replace(`/job/applied/${id}`)
}
})
but user still can go to the previous page which doesn't make sense, how to handle that?
You could try a onunload function of some sort. If the user clicks the button that you want them to click you would have to set a variable so they dont get the warning message.
var showAlert= 1; // this is set to it will show warning when leaving the page
// if they click your next button add this to a function
// showAlert =0;
window.onbeforeunload = function(){
if (showAlert == 1)
return 'Please use the Next and Previous buttons and not the browser back buttons to ensure your date is saved.';
};

Save and retreive users layout preference from on click function using localstorage

I'm new to using localstorage but believe this is what I would need to use for storing a particular ID or CLASS from my css file to render in a users browser once they made their selection (on click event) to display a "grid / list" layout. Is localstorage preferred here? Or would it be better to use "sessionstorage"? Or would it be better to use a completely different method altogether? And if so, what?
What I am trying to achieve is this:
User clicks on 1 of 2 icons - These icons need to store the css layout ID or CLASS I've made (either "cozy" or "list" view). As the user goes through other pages of the website, this preference is remembered so if the user goes back to this page, the layout is still the same from what he/she selected. Same would apply if the user closed their browser and then re-opened it to that page.
Adding a cached for time would be preferred as well. For example, keeping the layout in the users localstorage for "x" amount of days before it is cleared.
Any help would be greatly appreciated as I have no idea how to even start this. I've looked at tons of examples, but can't seem to wrap my head around how they did it and worse yet, the examples I've seen seem not to cater to my needs.
Here is what I have so far:
JS
// Changing layout 'Cozy' to 'List'
$('.news_nav-options_list').on('click', function () {
var cozy=document.getElementById('hideClass');
cozy.style.display="none";
var list=document.getElementById('showClass');
list.style.display="block";
$(this).addClass('active');
$('.news_nav-options_cozy').removeClass('active');
});
// Changing layout 'List' to 'Cozy'
$('.news_nav-options_cozy').on('click', function () {
var list=document.getElementById('hideClass');
list.style.display="block";
var cozy=document.getElementById('showClass');
cozy.style.display="none";
$(this).addClass('active');
$('.news_nav-options_list').removeClass('active');
});
And here is a demo of what I have so far:
DEMO
I read using the ".setItem() and .getItem" with localstorage is preferred but again, I have no idea how I should even start. Can localstorage be applied to what I currently have for my js?
This isn't quite correct, but I think it should point you in the direction you are looking for.
$(document).ready(function(){
// Changing layout 'Cozy' to 'List'
$('.news_nav-options_list').on('click', function () {
changeToListView();
});
// Changing layout 'List' to 'Cozy'
$('.news_nav-options_cozy').on('click', function () {
changeToCozyView();
});
if (typeof(Storage) !== "undefined") {
var view = localStorage.getItem("view");
if (view && view == "cozy") {
changeToCozyView();
} else if (view && view == "list") {
changeToListView();
} else {
// view isn't set, or is set to something we don't recognize
}
} else {
// user's browser doesn't support localStorage
}
});
function changeToListView() {
var cozy=document.getElementById('hideClass');
cozy.style.display="none";
var list=document.getElementById('showClass');
list.style.display="block";
storagePut("list");
$(this).addClass('active');
$('.news_nav-options_cozy').removeClass('active');
}
function changeToCozyView() {
var list=document.getElementById('hideClass');
list.style.display="block";
var cozy=document.getElementById('showClass');
cozy.style.display="none";
storagePut("cozy");
$(this).addClass('active');
$('.news_nav-options_list').removeClass('active');
}
function storagePut(view) {
if (typeof(Storage) !== "undefined") {
localStorage.setItem("view", view);
} else {
// user's browser doesn't support localStorage
}
}

Run JS SetTimeout function only once per domain

I've implemented a Splash Screen in JQuery on my WordPress Site on Document ready.
setTimeout(function() {
$("#site-overlay").fadeOut();
}, 3000);
Ok, the Overlay fades out after 3 seconds. But if I click on a menu button, the whole page reloads and the function settimeout repeats because its on the document ready.
How can I set this only for one time per Domain without using complicated code?
What you will have to do is implement cookies or something alike
I would suggest https://github.com/yanivkalfa/myCookie which is my own library but there are other like its so you can pick one.
The point is to set a flag or something in a cookie or session that says that you already done the action you want.
e.g:
// <script .... https://github.com/yanivkalfa/myCookie .. inclode my cookies library
setTimeout(function() {
var overlayFlag = $.fn.myCookie({cName: "overlayFlag"});
if (!overlayFlag) {
$.fn.myCookie( {cName : "overlayFlag", cVal : true} );
$("#site-overlay").fadeOut();
}
}, 3000);
Something along these lines, there are other solutions .. this seemed a simple.
Another solution would be to use the document.referrer which I find better than the cookie, because if I close the page and reopening it, it would not do the fadeOut code.
So, I extract the domain from the referrer and compare with current one.
setTimeout(function() {
var referrerDomain = document.referrer;
if (referrerDomain != "") {
referrerDomain = referrerDomain.substring(document.referrer.indexOf('//') + 2);
referrerDomain = referrerDomain.substring(0, referrerDomain.indexOf('/'));
}
if (referrerDomain != window.location.host) {
$("#site-overlay").fadeOut();
}
}, 3000);
Ok, i got the solution for me :) session cookie was the answer.
/* check if session cookie is set, if not so set the cookie and animate the Overlay
* The session cookie will destroy if the BROWSER is closed (not TAB)
*/
if( document.cookie.indexOf("overlayed=") < 0)
{
document.cookie = "overlayed=true; path=/";
$("#site-overlay").show();
$("#site-overlay-content").show().center();
setTimeout(function()
{
$("#site-overlay").fadeOut(750);
}, 3000);
}

Categories