Guys I have this code that saves my products in cache, I would like to better understand how it works,
getItemById(id) {
// return this.http.get(`${environment.API_URL}item/getById/${id}`);
return
this.cacheS.getOrSetCache(`StoreService_getItemById_${id}_${this.layout.emp.id}`,
this.http.get(`${environment.API_URL}item/getById/${id}`), 300000);
}
getOrSetCache(key: string, request: Observable<any>, msToExpire = 300000): Observable<any> {
let cache: any = {};
cache = JSON.parse(localStorage.getItem(key));
return (cache?.data && (cache?.exp > Date.now())) ?
of(cache.data) :
request.pipe(tap(v => {
localStorage.setItem(key, JSON.stringify({data: v, exp: (Date.now() + msToExpire)}));
}));
}
My question is more about how it manages to save in cache with an expiration date, and when the date expires, make the request again
This code works, but I couldn't understand how, is there any other better way to cache with expiration date?
when you call getOrSetCache, you pass msToExpire to arguments. Date.now() returns the current time. If this element is not in the cache, you make a request and after receive data, you save in to ls, and set time to expire as date.now() + msToExpire. And in the next call of this function you compare exp from your save element with current time Date.now().
For example the cache is empty, and you call getOrSetCache at 17:00. And let's imagine that the msToExpire = 30 min. Since the cache is empty, we make a request and save the data to the cache exp: (Date.now() + msToExpire) = 17:00 + 30 min = 17:30. Now, if call your function at 17:20 o'clock, this condition cache?.data && (cache?.exp > Date.now())) returns true, cause 17:30 > 17:20 and you will receive data from cache. But if you call it at 17:31, condition will return false, and it make new request and rewrite data in cache with new timestamp
I am new to session storage and I am trying to take two stored values and substract them then play it back in innerhtml. I don't know how to do that.
(index):897 Uncaught TypeError: Cannot read property 'getElementById' of undefined
let propertyPrice = document.getElementById("propertyPrice");
if (sessionStorage.getItem("propertyPriceStored")) {
propertyPrice.value = sessionStorage.getItem("propertyPriceStored");
}
propertyPrice.addEventListener("change", function() {
sessionStorage.setItem("propertyPriceStored", propertyPrice.value);
});
let deposit = document.getElementById("deposit");
if (sessionStorage.getItem("depositStored")) {
deposit.value = sessionStorage.getItem("depositStored");
}
deposit.addEventListener("change", function() {
sessionStorage.setItem("depositStored", deposit.value);
});
let loanAmount = propertyPrice - deposit;
loanAmount.document.getElementById("loanAmountResult").innerHTML;
I have managed to get the console log to show numbers on reloading of the page but i can get it to happen then and there on the page.
let deposit = document.getElementById("deposit");
// See if we have an autosave value
// (this will only happen if the page is accidentally refreshed)
if (sessionStorage.getItem("depositStored")) {
// Restore the contents of the text field
deposit.value = sessionStorage.getItem("depositStored");
}
// Listen for changes in the text field
deposit.addEventListener("change", function() {
// And save the results into the session storage object
sessionStorage.setItem("depositStored", deposit.value);
});
let loanAmount = propertyPrice.value - deposit.value;
console.log(loanAmount)
loanAmount.addEventListener("change", function() {
document.getElementById("loanAmountResult").innerHTML;
});
I am trying to set a cookie which stores the current TimezoneOffset.
window.onload = function () {
var timezone_cookie = "timezoneoffset";
if (!$.cookie(timezone_cookie)) { // if the timezone cookie not exists create one.
// check if the browser supports cookie
var test_cookie = 'test cookie';
$.cookie(test_cookie, true);
if ($.cookie(test_cookie)) { // browser supports cookie
// delete the test cookie.
$.cookie(test_cookie, null);
// create a new cookie
$.cookie(timezone_cookie, new Date().getTimezoneOffset());
location.reload(); // re-load the page
}
}
else { // if the current timezone and the one stored in cookie are different then
// store the new timezone in the cookie and refresh the page.
var storedOffset = parseInt($.cookie(timezone_cookie));
var currentOffset = new Date().getTimezoneOffset();
if (storedOffset !== currentOffset) { // user may have changed the timezone
$.cookie(timezone_cookie, new Date().getTimezoneOffset());
location.reload();
}
}
};
But when I try to read the value later, the debugging Tool in Visual Studio tells me, it is "null".
If I load the page and inspect the cookies, a value (-120) is set.
Can someone tell me what I am doing wrong?
The javascript is within the _Layout.cshtml file. The code I want to execute with the cookie looks like this:
var timeOffSet = HttpContext.Current.Session["timezoneoffset"]; // read the value from session
if (timeOffSet != null)
{
var offset = int.Parse(timeOffSet.ToString());
dt = dt.AddMinutes(-1 * offset);
return dt.ToString("yyyy-MM-dd HH:mm");
}
// if there is no offset in session return the datetime in server timezone
return dt.ToLocalTime().ToString("yyyy-MM-dd HH:mm");
Function is called from a View, so the js code should have been executed by this time.
I think that you try to get the value in a wrong way - the cookies are not stored in session variable.
You can use this line instead:
HttpCookie cookie = Request.Cookies["timezoneoffset"];
if ((cookie != null) && (cookie.Value != ""))
{
var offset = int.Parse(cookie.Value.ToString());
dt = dt.AddMinutes(-1 * offset);
return dt.ToString("yyyy-MM-dd HH:mm");
}
return dt.ToLocalTime().ToString("yyyy-MM-dd HH:mm");
I would like to have a timer for content in localStorage.
For example I have got a dynamically updated DIV
<div id="news"><p>test</p></div>
And managed to add it as html block to localStorage by using this code:
$(function() {
localStorage["homeNews"] = JSON.stringify($("#news").html());
});
$(function() {
if (localStorage["homeNews"] != null) {
var contentsOfNews = JSON.parse(localStorage["homeNews"]);
$("#news").html(contentsOfNews);
}
});
I need to add a time stamp to the localStorage["homeNews"] and a snippet which will remove it after 5 minutes by checking the current time and the time stamp of my localStorage.
The fiddle is here: http://jsfiddle.net/Rn4NC/
LocalStorage Content Timestamp with TTL Time To Live to Remove Itself
JSFiddle: http://jsfiddle.net/Rn4NC/3/
The goal is to provide an interface that is easy to use to pull in data that is not too old based on a time supplied by the programmer. Here is the simple interface:
Usage of DB Example with TTL
HTML
<div id="news"><p>test</p></div>
JavaScript
$(function() {
// Set Value with TTL of 5 Seconds using Milliseconds.
db.set( "homeNews", $("#news").html(), 5000 );
});
$(function() {
// Get Value
var contentsOfNews = db.get("homeNews");
// Show Value
$("#news").html(contentsOfNews);
});
That's the example usage case, next is the interface definition with TTL support:
Local Storage with TTL Interface Definition.
Here is the interface logic for db usage and is used in the example above. Checkout the JSFiddle example for the full usage.
$(function(){
function now () {return+new Date}
var db = window.db = {
get : function(key) {
var entry = JSON.parse(localStorage.getItem(key)||"0");
if (!entry) return null;
if (entry.ttl && entry.ttl + entry.now < now()) {
localStorage.removeItem(key);
return null;
}
return entry.value;
},
set : function( key, value, ttl ) {
localStorage.setItem( key, JSON.stringify({
ttl : ttl || 0,
now : now(),
value : value
}) );
}
};
});
For how long is data stored in localStorage (as part of DOM Storage in HTML5) available? Can I set an expiration time for the data which I put into local storage?
I would suggest to store timestamp in the object you store in the localStorage
var object = {value: "value", timestamp: new Date().getTime()}
localStorage.setItem("key", JSON.stringify(object));
You can parse the object, get the timestamp and compare with the current Date, and if necessary, update the value of the object.
var object = JSON.parse(localStorage.getItem("key")),
dateString = object.timestamp,
now = new Date().getTime().toString();
compareTime(dateString, now); //to implement
Alternatively, you could use a light-weight wrapper like localstorage-slim.js which handles this for you.
It's not possible to specify expiration. It's completely up to the user.
https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
Of course, it's possible that something your application stores on the client may not be there later. The user can explicitly get rid of local storage, or the browser may run into space considerations. It's good to program defensively. Generally however things remain "forever" based on some practical definition of that word.
edit — obviously, your own application can actively remove stuff if it decides it's too old. That is, you can explicitly include some sort of timestamp in what you've got saved, and then use that later to decide whether or not information should be flushed.
You can use lscache. It handles this for you automatically, including instances where the storage size exceeds the limit. If that happens, it begins pruning items that are the closest to their specified expiration.
From the readme:
lscache.set
Stores the value in localStorage. Expires after specified number of minutes.
Arguments
key (string)
value (Object|string)
time (number: optional)
This is the only real difference between the regular storage methods. Get, remove, etc work the same.
If you don't need that much functionality, you can simply store a time stamp with the value (via JSON) and check it for expiry.
Noteworthy, there's a good reason why local storage is left up to the user. But, things like lscache do come in handy when you need to store extremely temporary data.
Brynner Ferreira, has brought a good point: storing a sibling key where expiration info resides. This way, if you have a large amount of keys, or if your values are large Json objects, you don't need to parse them to access the timestamp.
here follows an improved version:
/* removeStorage: removes a key from localStorage and its sibling expiracy key
params:
key <string> : localStorage key to remove
returns:
<boolean> : telling if operation succeeded
*/
function removeStorage(name) {
try {
localStorage.removeItem(name);
localStorage.removeItem(name + '_expiresIn');
} catch(e) {
console.log('removeStorage: Error removing key ['+ key + '] from localStorage: ' + JSON.stringify(e) );
return false;
}
return true;
}
/* getStorage: retrieves a key from localStorage previously set with setStorage().
params:
key <string> : localStorage key
returns:
<string> : value of localStorage key
null : in case of expired key or failure
*/
function getStorage(key) {
var now = Date.now(); //epoch time, lets deal only with integer
// set expiration for storage
var expiresIn = localStorage.getItem(key+'_expiresIn');
if (expiresIn===undefined || expiresIn===null) { expiresIn = 0; }
if (expiresIn < now) {// Expired
removeStorage(key);
return null;
} else {
try {
var value = localStorage.getItem(key);
return value;
} catch(e) {
console.log('getStorage: Error reading key ['+ key + '] from localStorage: ' + JSON.stringify(e) );
return null;
}
}
}
/* setStorage: writes a key into localStorage setting a expire time
params:
key <string> : localStorage key
value <string> : localStorage value
expires <number> : number of seconds from now to expire the key
returns:
<boolean> : telling if operation succeeded
*/
function setStorage(key, value, expires) {
if (expires===undefined || expires===null) {
expires = (24*60*60); // default: seconds for 1 day
} else {
expires = Math.abs(expires); //make sure it's positive
}
var now = Date.now(); //millisecs since epoch time, lets deal only with integer
var schedule = now + expires*1000;
try {
localStorage.setItem(key, value);
localStorage.setItem(key + '_expiresIn', schedule);
} catch(e) {
console.log('setStorage: Error setting key ['+ key + '] in localStorage: ' + JSON.stringify(e) );
return false;
}
return true;
}
Here highly recommended to use sessionStorage
it is same as localStorage but destroy when session destroyed / browser close
also localStorage can share between tabs while sessionStorage can use in current tab only, but value does not change on refresh page or change the page
sessionStorage is also useful to reduce network traffic against cookie
for set value use
sessionStorage.setItem("key","my value");
for get value use
var value = sessionStorage.getItem("key");
click here for view api
all ways for set are
sessionStorage.key = "my val";
sessionStorage["key"] = "my val";
sessionStorage.setItem("key","my value");
all ways for get are
var value = sessionStorage.key;
var value = sessionStorage["key"];
var value = sessionStorage.getItem("key");
While local storage does not supply an expiration mechanism, cookies do. Simply pairing a local storage key with a cookie provides an easy way to ensure that local storage can be updated with the same expiration parameters as a cookie.
Example in jQuery:
if (!$.cookie('your_key') || !localStorage.getItem('your_key')) {
//get your_data from server, then...
localStorage.setItem('your_key', 'your_data' );
$.cookie('your_key', 1);
} else {
var your_data = localStorage.getItem('your_key');
}
// do stuff with your_data
This example sets a cookie with the default parameter to expire when the browser is closed. Thus, when the browser is closed and re-opened, the local data store for your_data gets refreshed by a server-side call.
Note that this is not exactly the same as removing the local data store, it is instead updating the local data store whenever the cookie expires. However, if your main goal is to be able to store more than 4K client-side (the limitation for cookie size), this pairing of cookie and local storage will help you to accomplish a larger storage size using the same expiration parameters as a cookie.
The lifecycle is controlled by the application/user.
From the standard:
User agents should expire data from the local storage areas only for security reasons or when requested to do so by the user. User agents should always avoid deleting data while a script that could access that data is running.
From the W3C draft:
User agents should expire data from the local storage areas only for security reasons or when requested to do so by the user. User agents should always avoid deleting data while a script that could access that data is running.
You'll want to do your updates on your schedule using setItem(key, value); that will either add or update the given key with the new data.
// Functions
function removeHtmlStorage(name) {
localStorage.removeItem(name);
localStorage.removeItem(name+'_time');
}
function setHtmlStorage(name, value, expires) {
if (expires==undefined || expires=='null') { var expires = 3600; } // default: 1h
var date = new Date();
var schedule = Math.round((date.setSeconds(date.getSeconds()+expires))/1000);
localStorage.setItem(name, value);
localStorage.setItem(name+'_time', schedule);
}
function statusHtmlStorage(name) {
var date = new Date();
var current = Math.round(+date/1000);
// Get Schedule
var stored_time = localStorage.getItem(name+'_time');
if (stored_time==undefined || stored_time=='null') { var stored_time = 0; }
// Expired
if (stored_time < current) {
// Remove
removeHtmlStorage(name);
return 0;
} else {
return 1;
}
}
// Status
var cache_status = statusHtmlStorage('cache_name');
// Has Data
if (cache_status == 1) {
// Get Cache
var data = localStorage.getItem('cache_name');
alert(data);
// Expired or Empty Cache
} else {
// Get Data
var data = 'Pay in cash :)';
alert(data);
// Set Cache (30 seconds)
if (cache) { setHtmlStorage('cache_name', data, 30); }
}
If you’re familiar with the browsers locaStorage object, you know that there’s no provision for providing an expiry time. However, we can use Javascript to add a TTL (Time to live) to invalidate items in locaStorage after a certain period of time elapses.
function setLocalStorageItem(key, value, ttl) {
// `item` is an object which contains the original value
// as well as the time when it's supposed to expire
let item = {
value: value,
expiry: ttl ? Date.now() + ttl : null
};
localStorage.setItem(key, JSON.stringify(item));
}
function getLocalStorageItem(key) {
let item = localStorage.getItem(key);
// if the item doesn't exist, return null
if (!item) return null;
item = JSON.parse(item);
// compare the expiry time of the item with the current time
if (item.expiry && Date.now() > item.expiry) {
// If the item is expired, delete the item from storage and return null
localStorage.removeItem(key);
return null;
}
return item.value;
}
You can try this one.
var hours = 24; // Reset when storage is more than 24hours
var now = Date.now();
var setupTime = localStorage.getItem('setupTime');
if (setupTime == null) {
localStorage.setItem('setupTime', now)
} else if (now - setupTime > hours*60*60*1000) {
localStorage.clear()
localStorage.setItem('setupTime', now);
}
If anyone still looking for a quick solution and don't want dependencies like jquery etc I wrote a mini lib that add expiration to local / session / custom storage, you can find it with source here:
https://github.com/RonenNess/ExpiredStorage
If someone using jStorage Plugin of jQuery the it can be add expiry with setTTL function if jStorage plugin
$.jStorage.set('myLocalVar', "some value");
$.jStorage.setTTL("myLocalVar", 24*60*60*1000); // 24 Hr.
Javascript localStorage do not have any options to set expire time
Then i use these functions to check supports, Set and Get
function ls_support(){
return "localStorage" in window&&window["localStorage"]!==null;
}
function lsset(key,val,exp){
if(ls_support()){
if(!exp) exp=600;// = 10 minutes Default
localStorage[key]=
JSON.stringify({
"val":val,
"exp":~~((new Date()).getTime()/1000)+exp
});
}
}
function lsget(key){
if(ls_support()){
str=localStorage[key];
if("undefined"!=typeof(str)&&str.length){
try{// is json or not
json=JSON.parse(str);
}catch(e){// if variable not set via lsset func
//json.exp=false;// will return null
return str;// will return original variable
}
if(json.exp){// variable setted via lsset func
if(~~((new Date()).getTime()/1000)>json.exp){// expired
delete localStorage[key];
}else{
return json.val;
}
}
}
}
return null;
}
And it seems works fine :
Workaround using angular and localforage:
angular.module('app').service('cacheService', function() {
return {
set: function(key, value, expireTimeInSeconds) {
return localforage.setItem(key, {
data: value,
timestamp: new Date().getTime(),
expireTimeInMilliseconds: expireTimeInSeconds * 1000
})
},
get: function(key) {
return localforage.getItem(key).then(function(item) {
if(!item || new Date().getTime() > (item.timestamp + item.expireTimeInMilliseconds)) {
return null
} else {
return item.data
}
})
}
}
})
#sebarmeli's approach is the best in my opinion, but if you only want data to persist for the life of a session then sessionStorage is probably a better option:
This is a global object (sessionStorage) that maintains a storage area
that's available for the duration of the page session. A page session
lasts for as long as the browser is open and survives over page
reloads and restores. Opening a page in a new tab or window will cause
a new session to be initiated.
MDN: sessionStorage
For the benefit of searchers:
Like Fernando, I didn't want to add a load of json when the values stored were simple. I just needed to track some UI interaction and keep the data relevant (e.g. how a user used an ecommerce site before checking out).
This will not meet everyones criteria, but will hopefully be a quick copy+paste starter for someone and save adding another lib.
NOTE: This would not be good if you need to retrieve the items individually.
// Addition
if(window.localStorage){
localStorage.setItem('myapp-' + new Date().getTime(), 'my value');
}
// Removal of all expired items
if(window.localStorage){
// two mins - (1000 * 60 * 20) would be 20 mins
var expiryTime = new Date().getTime() - (1000 * 60 * 2);
var deleteRows = [];
for(var i=0; i < localStorage.length; i++){
var key = localStorage.key(i);
var partsArray = key.split('-');
// The last value will be a timestamp
var lastRow = partsArray[partsArray.length - 1];
if(lastRow && parseInt(lastRow) < expiryTime){
deleteRows.push(key);
}
}
// delete old data
for(var j=0; j < deleteRows.length; j++){
localStorage.removeItem(deleteRows[j]);
}
}
function setStorage(name,value){
return localStorage.setItem(name,JSON.stringify({value:value,timestamp:Math.round((new Date()).getTime()/1000)}));
}
function getStorage(name,timeout){
var object = JSON.parse(localStorage.getItem(name));
if(object){
if(Math.round((new Date()).getTime()/1000) < (object.timestamp+timeout)){
return object.value;
}else{
localStorage.removeItem(name);
}
}
return false;
}