I have this problem that only exists on first page load in Chrome on desktop. It works in Chrome on the second or more page loads. It also works on mobile in Chrome on every page load.
It works fine in Safari and Firefox, MOST OF THE TIME. I have experienced the below error there as well, only on first page load, only on desktop, but I am not able to reproduce it there for about an entire day now.
Does anyone know what is going on?
The only thing I have been able to come up with is that somehow my redirect function is triggered. Because as you can see in the flow indicated below at number 6, after the error, the page redirects back to index.html. However that function would only trigger if the value of one of my sessionStorage values is null and I can see in the browser console that those values are set correctly when I press the button to go to the next page.
The error:
The flow:
Landing page is index.html with separate index.js
Upon selection of a few drop-downs, 3 values are stored in sessionStorage
Next page is called: normal-quiz.html with separate normal-quiz.js
Values from sessionStorage are retrieved to filter a data array
The loadQuiz function runs on the filtered array and sets a question element value to an object's 'english' property
On first page load, only in Chrome on desktop, the above error occurs which makes the browser return to index.html and sessionStorage is cleared
If I try the above again, it works without a problem
The line generating the error is where I use the loadQuiz function to set the question element's value in my html to the 'english' property value of the first object in the filtered array.
The code (js):
function redirect() {
if (selectedBook !== null) {
// do nothing
} else {
window.location = "<myURL>"
};
};
redirect();
function loadQuiz() {
const currentQuizData = quizArr[currentQuiz]; // currentQuiz is the question counter. It starts at 0 to get the first object, then increments by 1 after each question
questionEl.innerText = currentQuizData.english;
// line above is where the error is generated
counter.innerText = (currentQuiz + 1) + "/" + quizArr.length;
};
loadQuiz();
I'm working on a project and I have to make a button to remember users selected specific page. It should work like a cookie, but I need some more information about how to save website page on cookies. The main part is when users clicks on a button, website remember users selection and when users enter after some time the same page, he will see his selection. And of course, if user push the button one more time, his selection deletes.
P.s. I'm new guy in coding so, your help will be useful for me.
Thanks in advance.
You can use browser storage for this
When user select some value:
localStorage.setItem("userSelection", "selection-value");
And when the user enter on page, you verify if userSelection exists:
var userSelection = localStorage.getItem('userSelection');
if ( userSelection ) {
// some action
}
See more: localStorage
Use any of these below to store user preferences
sessionStorage.setItem("sessionData", "I am set in session storage.");
localStorage.setItem("localData", "I am set in local storage.");
My recommendation is to store preference using URL hash combination while.storing in session or localstorage
you can do that based on ids like in my example right bellow
function getCookie(name){
var b=name+"=",
c=decodeURIComponent(document.cookie),
d=c.split(";");
for(var e=0;e<d.length;e++){
for(var f=d[e];" "==f.charAt(0);)f=f.substring(1);
if(0==f.indexOf(b))return f.substring(b.length,f.length)
}
}
function setCookie(name,value,period,path){
var time=new Date;
time.setTime(time.getTime()+1e3*(60*(60*(24*period))));
document.cookie=name+"="+value+";"+"expires="+time.toUTCString()+";path="+(path?path:"/")
}
function removeCookie(cookie_name){
if(getCookie(cookie_name)){
document.cookie=cookie_name+"=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
}
}
document.getElementById('xxx').onclick = function(){
if(getCookie(this.id)==1) {
removeCookie(this.id)
} else {
setCookie(this.id,1,999999);
}
}
<button id="xxx">Selection 1</button>
and of course use php or maybe javascript to detect if cookie exists.
This is a follow up to my original question here. The answers proposed work in Firefox, but there are problems with at least Chrome and Safari (on iOS).
The initial issue is this: on an unrelated site (say Facebook), users can create links where the href is in the form http//www.siteA.com/?http://www.siteB.com. The intention is that siteA parses the querystring and re-directs the browser to siteB. That all works fine.
Then, when a user, having been re-directed to siteB, clicks the back button on their browser, the goal is that they should return to siteA and not be re-directed again.
The answer to my previous question proposed that at the time of the re-direction from siteA, the code on siteA checks for a cookie - if it is not there, it sets it and re-directs. If it is there, then no redirection. In order to allow the user to return to the original referring page and click the same link again (and be re-directed to siteB), it was also proposed that if the cookie is found on siteA, as well as no re-direction, the cookie is deleted.
On Firefox that all works. The 2 problems now are:
on Chrome (and maybe others), the cookie deletion either doesn't work, or works only after the user navigates to another site. The deletion code is just simple javascript, setting the same cookie with an expiry date in the past. This may in practice be a relatively minor issue, but it would be nice to find a solution.
on Safari on iOS, siteA is not in the browser history. It seems iOS (and maybe Safari generally), tries to avoid the looping problem) of returning to a page that re-directed to a second site), by omitting the re-directing page from the history stack. As a result, the pressing the back button on siteB goes to the page prior to the re-directing page. This is a major issue.
It seems there are 3 possibilities - what I want to do is not possible because it's a security risk; there's no crosss-browser/platform solution; or I've approached the goal by completely the wrong method.
The fixed points are:
the form of the URL (with a querystring containing the second URL);
no access to the server (limited to javascript/jquery).
no control over siteB (only siteA).
I'd be grateful for any suggestions and/or advice.
Thanks
This appears to be a solution to issue 2:
$(document).ready(function() {
var s = location.search;
if(s != '') {
var split = s.split('?');
var loc = split[1].replace('?', '');
if (document.cookie.indexOf('redirected=' + loc + '') == -1) {
document.cookie = 'redirected=' + loc + '';
var link = document.createElement('a');
link.href = loc;
document.body.appendChild(link);
link.click();
} else {
document.cookie = 'redirected=' + loc + '; expires=Thu, 01 Jan 1970 00:00:00 GMT';
var url = location.href.replace('' + s + '', '');
location.href = '' + url + '';
}
} else
{
//do something on the re-direction page
}
});
It's a bit old school, but instead of re-directing, you create a link on the intermediate page and click it programmatically. That works like a re-direction, but leaves the re-directing page in the history stack, even on iOS.
Thanks to this answer on SO for the hint.
Still looking for a way to remove the cookie more effectively though.
I'd be interested and grateful to read any other comments on these issues. Thanks.
My Case: localStorage with key + value that should be deleted when browser is closed and not single tab.
Please see my code if its proper and what can be improved:
//create localStorage key + value if not exist
if (localStorage) {
localStorage.myPageDataArr = {
"name" => "Dan",
"lastname" => "Bonny"
};
}
//when browser closed - psedocode
$(window).unload(function() {
localStorage.myPageDataArr = undefined;
});
should be done like that and not with delete operator:
localStorage.removeItem(key);
Use with window global keyword:-
window.localStorage.removeItem('keyName');
You should use the sessionStorage instead if you want the key to be deleted when the browser close.
You can make use of the beforeunload event in JavaScript.
Using vanilla JavaScript you could do something like:
window.onbeforeunload = function() {
localStorage.removeItem(key);
return '';
};
That will delete the key before the browser window/tab is closed and prompts you to confirm the close window/tab action. I hope that solves your problem.
NOTE: The onbeforeunload method should return a string.
localStorage.removeItem(key); //item
localStorage.clear(); //all items
There is a very specific use case in which any suggestion to use sessionStorage instead of localStorage does not really help.
The use-case would be something as simple as having something stored while you have at least one tab opened, but invalidate it if you close the last tab remaining.
If you need your values to be saved cross-tab and window, sessionStorage does not help you unless you complicate your life with listeners, like I have tried.
In the meantime localStorage would be perfect for this, but it does the job 'too well', since your data will be waiting there even after a restart of the browser.
I ended up using a custom code and logic that takes advantage of both.
I'd rather explain then give code. First store what you need to in localStorage, then also in localStorage create a counter that will contain the number of tabs that you have opened.
This will be increased every time the page loads and decreased every time the page unloads. You can have your pick here of the events to use, I'd suggest 'load' and 'unload'.
At the time you unload, you need to do the cleanup tasks that you'd like to when the counter reaches 0, meaning you're closing the last tab.
Here comes the tricky part: I haven't found a reliable and generic way to tell the difference between a page reload or navigation inside the page and the closing of the tab.
So If the data you store is not something that you can rebuild on load after checking that this is your first tab, then you cannot remove it at every refresh.
Instead you need to store a flag in sessionStorage at every load before increasing the tab counter.
Before storing this value, you can make a check to see if it already has a value and if it doesn't,
this means you're loading into this session for the first time, meaning that you can do the cleanup at load if this value is not set and the counter is 0.
use sessionStorage
The sessionStorage object is equal to the localStorage object, except that it stores the data for only one session. The data is deleted when the user closes the browser window.
The following example counts the number of times a user has clicked a button, in the current session:
Example
if (sessionStorage.clickcount) {
sessionStorage.clickcount = Number(sessionStorage.clickcount) + 1;
} else {
sessionStorage.clickcount = 1;
}
document.getElementById("result").innerHTML = "You have clicked the button " +
sessionStorage.clickcount + " time(s) in this session.";
Try using
$(window).unload(function(){
localStorage.clear();
});
Hope this works for you
There are five methods to choose from:
setItem(): Add key and value to localStorage
getItem(): Retrieve a value by the key from localStorage
removeItem(): Remove an item by key from localStorage
clear(): Clear all localStorage
key(): Passed a number to retrieve nth key of a localStorage
You can use clear(), this method when invoked clears the entire storage of all records for that domain. It does not receive any parameters.
window.localStorage.clear();
for (let i = 0; i < localStorage.length; i++) {
if (localStorage.key(i).indexOf('the-name-to-delete') > -1) {
arr.push(localStorage.key(i));
}
}
for (let i = 0; i < arr.length; i++) {
localStorage.removeItem(arr[i]);
}
8.5 years in and the original question was never actually answered.
when browser is closed and not single tab.
This basic code snippet will give you the best of both worlds. Storage that persists only as long as the browser session (like sessionStorage), but is also shareable between tabs (localStorage).
It does this purely through localStorage.
function cleanup(){
// place whatever cleanup logic you want here, for example:
// window.localStorage.removeItem('my-item')
}
function tabOpened(){
const tabs = JSON.parse(window.localStorage.getItem('tabs'))
if (tabs === null) {
window.localStorage.setItem('tabs', 1)
} else {
window.localStorage.setItem('tabs', ++tabs)
}
}
function tabClosed(){
const tabs = JSON.parse(window.localStorage.getItem('tabs'))
if (tabs === 1) {
// last tab closed, perform cleanup.
window.localStorage.removeItem('tabs')
cleanup()
} else {
window.localStorage.setItem('tabs', --tabs)
}
}
window.onload = function () {
tabOpened();
}
window.onbeforeunload = function () {
tabClosed();
}
why not used sessionStorage?
"The sessionStorage object is equal to the localStorage object, except that it stores the data for only one session. The data is deleted when the user closes the browser window."
http://www.w3schools.com/html/html5_webstorage.asp
Although, some users already answered this question already, I am giving an example of application settings to solve this problem.
I had the same issue. I am using https://github.com/grevory/angular-local-storage module in my angularjs application. If you configure your app as follows, it will save variable in session storage instead of local storage. Therefore, if you close the browser or close the tab, session storage will be removed automatically. You do not need to do anything.
app.config(function (localStorageServiceProvider) {
localStorageServiceProvider
.setPrefix('myApp')
.setStorageType('sessionStorage')
});
Hope it will help.
Here's a simple test to see if you have browser support when working with local storage:
if(typeof(Storage)!=="undefined") {
console.log("localStorage and sessionStorage support!");
console.log("About to save:");
console.log(localStorage);
localStorage["somekey"] = 'hello';
console.log("Key saved:");
console.log(localStorage);
localStorage.removeItem("somekey"); //<--- key deleted here
console.log("key deleted:");
console.log(localStorage);
console.log("DONE ===");
} else {
console.log("Sorry! No web storage support..");
}
It worked for me as expected (I use Google Chrome).
Adapted from: http://www.w3schools.com/html/html5_webstorage.asp.
I don't think the solution presented here is 100% correct because window.onbeforeunload event is called not only when browser/Tab is closed(WHICH IS REQUIRED), but also on all other several events. (WHICH MIGHT NOT BE REQUIRED)
See this link for more information on list of events that can fire window.onbeforeunload:-
http://msdn.microsoft.com/en-us/library/ms536907(VS.85).aspx
After looking at this question 6 years after it was asked, I found that there still is no sufficient answer to this question; which should achieve all of the following:
Clear Local Storage after closing the browser (or all tabs of the domain)
Preserve Local Storage across tabs, if at least one tab remains active
Preserve Local Storage when reloading a single tab
Execute this piece of javascript at the start of each page load in order to achieve the above:
((nm,tm) => {
const
l = localStorage,
s = sessionStorage,
tabid = s.getItem(tm) || (newid => s.setItem(tm, newid) || newid)((Math.random() * 1e8).toFixed()),
update = set => {
let cur = JSON.parse(l.getItem(nm) || '{}');
if (set && typeof cur[tabid] == 'undefined' && !Object.values(cur).reduce((a, b) => a + b, 0)) {
l.clear();
cur = {};
}
cur[tabid] = set;
l.setItem(nm, JSON.stringify(cur));
};
update(1);
window.onbeforeunload = () => update(0);
})('tabs','tabid');
Edit: The basic idea here is the following:
When starting from scratch, the session storage is assigned a random id in a key called tabid
The local storage is then set with a key called tabs containing a object those key tabid is set to 1.
When the tab is unloaded, the local storage's tabs is updated to an object containing tabid set to 0.
If the tab is reloaded, it's first unloaded, and resumed. Since the session storage's key tabid exists, and so does the local storage tabs key with a sub-key of tabid the local storage is not cleared.
When the browser is unloaded, all session storage will be cleared. When resuming the session storage tabid won't exists anymore and a new tabid will be generated. Since the local storage does not have a sub-key for this tabid, nor any other tabid (all session were closed), it's cleared.
Upon a new created tab, a new tabid is generated in session storage, but since at least one tabs[tabid] exists, the local storage is not cleared
This will do the trick for objects.
localStorage.removeItem('key');
Or
localStorage.setItem('key', 0 );
You can simply use sessionStorage. Because sessionStorage allow to clear all key value when browser window will be closed .
See there : SessionStorage- MDN
This is an old question, but it seems none of the answer above are perfect.
In the case you want to store authentication or any sensitive information that are destructed only when the browser is closed, you can rely on sessionStorage and localStorage for cross-tab message passing.
Basically, the idea is:
You bootstrap from no previous tab opened, thus both your localStorage and sessionStorage are empty (if not, you can clear the localStorage). You'll have to register a message event listener on the localStorage.
The user authenticate/create a sensitive info on this tab (or any other tab opened on your domain).
You update the sessionStorage to store the sensitive information, and use the localStorage to store this information, then delete it (you don't care about timing here, since the event was queued when the data changed). Any other tab opened at that time will be called back on the message event, and will update their sessionStorage with the sensitive information.
If the user open a new tab on your domain, its sessionStorage will be empty. The code will have to set a key in the localStorage (for exemple: req). Any(all) other tab will be called back in the message event, see that key, and can answer with the sensitive information from their sessionStorage (like in 3), if they have such.
Please notice that this scheme does not depend on window.onbeforeunload event which is fragile (since the browser can be closed/crashed without these events being fired). Also, the time the sensitive information is stored on the localStorage is very small (since you rely on transcients change detection for cross tab message event) so it's unlikely that such sensitive information leaks on the user's hard drive.
Here's a demo of this concept: http://jsfiddle.net/oypdwxz7/2/
There are no such the way to detect browser close so probably you can't delete localStorage on browser close but there are another way to handle the things you can uses sessionCookies as it will destroy after browser close.This is I implemented in my project.
if(localStorage.getItem("visit") === null) {
localStorage.setItem('visit', window.location.hostname);
console.log(localStorage.getItem('visit'));
}
else if(localStorage.getItem('visit') == 'localhost'){
console.log(localStorage.getItem('visit'));
}
else {
console.log(localStorage.getItem('visit'));
}
$(document).ready(function(){
$("#clickme").click(function(){
localStorage.setItem('visit', '0');
});
});
window.localStorage.removeItem('visit');
window.addEventListener('beforeunload', (event) => {
localStorage.setItem("new_qus_id", $('.responseId').attr('id'));
var new_qus_no = localStorage.getItem('new_qus_id');
console.log(new_qus_no);
});
if (localStorage.getItem('new_qus_id') != '') {
var question_id = localStorage.getItem('new_qus_id');
} else {
var question_id = "<?php echo $question_id ; ?>";
}
you can try following code to delete local storage:
delete localStorage.myPageDataArr;
I have a "new items" badge on a page that I want to update immediately the page is loaded from the cache (i.e. when hitting "Back" or "Forward" to return to this page). What is the best way to accomplish this?
The setup is pretty simple. The layout for the app looks for new items every 8 seconds, and updates the badge + list of items accordingly.
$(function() {
setInterval( App.pollForNewItems, 8000 );
});
When someone navigates away from this page to look at the details of an item, a lot can happen. Things are "new" until any user has viewed them, and the app will likely have several user using it simultaneously (the kind of workflow used for a call center or support tickets).
To make sure that the badges are always up to date, I have:
$(window).bind('focus load', function ( event ) {
App.pollForNewItems();
});
..And though this works, polling for new items on 'load' is only useful when the page is loaded from the cache. Is there a reliable cross-browser way to tell if a page is being loaded from the cache?
Navigation Timing is in most browsers now(ie9+)
http://www.w3.org/TR/navigation-timing/#sec-navigation-info-interface
if (!!window.performance && window.performance.navigation.type === 2) {
// page has been hit using back or forward buttons
} else {
// regular page hit
}
You can ask the web browser to not cache the page. Try these HTTP headers:
Cache-control: no-cache
Cache-control: no-store
Pragma: no-cache
Expires: 0
Particularly, Cache-control: no-store is interesting because it tells the browser to not store the page in memory at all which prevents a stale page being loaded when you hit the back/forward button.
If you do this instead, you don't have to poll for data on page load.
A partial hacky solution is to have a var with the current time set on the server, and set a var with the current client time at the top of the page. If they differ by more than a certain threshold (1 minute?) then you could assume it's a cached page load.
Example JS (using ASP.Net syntax for the server side):
var serverTime = new Date('<%= DateTime.Now.ToUniversalTime().ToString() %>');
var pageStartTime = Date.UTC(new Date());
var isCached = serverTime < pageStartTime &&
pageStartTime.getTime() - serverTime.getTime() > 60000;
Alternatively, using cookies on the client side (assuming cookies are enabled), you can check for a cookie with a unique key for the current version of the page. If none exists, you write a cookie for it, and on any other page access, the existence of the cookie shows you that it's being loaded from the cache.
E.g. (assumes some cookie helper functions are available)
var uniqueKey = '<%= SomeUniqueValueGenerator() %>';
var currentCookie = getCookie(uniqueKey);
var isCached = currentCookie !== null;
setCookie(uniqueKey); //cookies should be set to expire
//in some reasonable timeframe
Personally, I would set data attribute containing the item id for each element.
I.e.
<ul>
<li data-item-id="123">Some item.</li>
<li data-item-id="122">Some other item.</li>
<li data-item-id="121">Another one..</li>
</ul>
Your App.pollForNewItems function would grab the data-item-id attribute of the first element (if newest are first) and send it to the server with your original request.
The server would then only return the items WHERE id > ... which you can then prepend them to the list.
I'm still confused as to why you want to know if the browser has a cached version of the page.
Also, is there a reason for binding to load instead of ready?
Christian
good answer: https://stackoverflow.com/a/9870920/466363
You could also use Navigation Timing to measure the network latency in great detail.
Here is a good article: http://www.html5rocks.com/en/tutorials/webperformance/basics/
If the time difference between fetchStart and responseStart is very low, the page was loaded from cache, for example.
by stewe