- This topic is empty.
-
AuthorPosts
-
September 28, 2016 at 5:30 am #9144
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
David Hoang
KeymasterI made another minimalistic wrapper with only 20 lines of code to allow using it like it should:
localStorage.set('myKey',{a:[1,2,5], b: 'ok'}); localStorage.has('myKey'); // --> true localStorage.get('myKey'); // --> {a:[1,2,5], b: 'ok'} localStorage.keys(); // --> ['myKey'] localStorage.remove('myKey');May 17, 2017 at 7:58 am #9150
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
David Hoang
KeymasterlocalDataStorage is a synchronous JavaScript interface for the HTML5 localStorage API that–
- transparently sets/gets key values using data "types" such as Array, BigInt, Boolean, Date, Float, Integer, Object and String;
- provides lightweight data obfuscation;
- intelligently compresses strings (to save storage space);
- facilitates robust lookup including query by key (name), query by (key) value and query by existence (boolean check);
- enforces segmented shared storage within the same domain by prefixing keys;
- allows you to respond to localStorage change events on the same page/tab that fired them;
- broadcasts change events across the origin for the benefit of other windows/tabs;
- lets you easily work with arrays using dedicated Array Keys; and
- offers Memory Keys (that can be backed up to disk) for the fastest read times possible.
[DISCLAIMER] I am the author of the utility [/DISCLAIMER]
Basic examples:
localDataStorage.set( 'key1', 'Belgian' ) localDataStorage.set( 'key2', 1200.0047 ) localDataStorage.set( 'key3', true ) localDataStorage.set( 'key4', { 'RSK' : [1,'3',5,'7',9] } ) localDataStorage.set( 'key5', null ) localDataStorage.get( 'key1' ) // --> 'Belgian' localDataStorage.get( 'key2' ) // --> 1200.0047 localDataStorage.get( 'key3' ) // --> true localDataStorage.get( 'key4' ) // --> Object {RSK: Array(5)} localDataStorage.get( 'key5' ) // --> nullAs you can see, the primitive values are respected.
May 30, 2018 at 2:34 am #9148
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
David Hoang
KeymasterFor TypeScript users willing to set and get typed properties:
/** * Silly wrapper to be able to type the storage keys */ export class TypedStorage<T> { public removeItem(key: keyof T): void { localStorage.removeItem(key); } public getItem<K extends keyof T>(key: K): T[K] | null { const data: string | null = localStorage.getItem(key); return JSON.parse(data); } public setItem<K extends keyof T>(key: K, value: T[K]): void { const data: string = JSON.stringify(value); localStorage.setItem(key, data); } }// write an interface for the storage interface MyStore { age: number, name: string, address: {city:string} } const storage: TypedStorage<MyStore> = new TypedStorage<MyStore>(); storage.setItem("wrong key", ""); // error unknown key storage.setItem("age", "hello"); // error, age should be number storage.setItem("address", {city:"Here"}); // ok const address: {city:string} = storage.getItem("address");November 13, 2019 at 2:38 am #9141
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
David Hoang
KeymasterI found a way to make it work with objects that have cyclic references.
Let’s make an object with cyclic references.
obj = { L: { L: { v: 'lorem' }, R: { v: 'ipsum' } }, R: { L: { v: 'dolor' }, R: { L: { v: 'sit' }, R: { v: 'amet' } } } } obj.R.L.uncle = obj.L; obj.R.R.uncle = obj.L; obj.R.R.L.uncle = obj.R.L; obj.R.R.R.uncle = obj.R.L; obj.L.L.uncle = obj.R; obj.L.R.uncle = obj.R;We can’t do
JSON.stringifyhere, because of the circular references.LOCALSTORAGE.CYCLICJSONhas.stringifyand.parsejust like normalJSON, but works with objects with circular references. (“Works” meaning parse(stringify(obj)) and obj are deep equal AND have identical sets of ‘inner equalities’)But we can just use the shortcuts:
LOCALSTORAGE.setObject('latinUncles', obj) recovered = LOCALSTORAGE.getObject('latinUncles')Then,
recoveredwill be “the same” to obj, in the following sense:[ obj.L.L.v === recovered.L.L.v, obj.L.R.v === recovered.L.R.v, obj.R.L.v === recovered.R.L.v, obj.R.R.L.v === recovered.R.R.L.v, obj.R.R.R.v === recovered.R.R.R.v, obj.R.L.uncle === obj.L, obj.R.R.uncle === obj.L, obj.R.R.L.uncle === obj.R.L, obj.R.R.R.uncle === obj.R.L, obj.L.L.uncle === obj.R, obj.L.R.uncle === obj.R, recovered.R.L.uncle === recovered.L, recovered.R.R.uncle === recovered.L, recovered.R.R.L.uncle === recovered.R.L, recovered.R.R.R.uncle === recovered.R.L, recovered.L.L.uncle === recovered.R, recovered.L.R.uncle === recovered.R ]Here is the implementation of
LOCALSTORAGELOCALSTORAGE = (function(){ "use strict"; var ignore = [Boolean, Date, Number, RegExp, String]; function primitive(item){ if (typeof item === 'object'){ if (item === null) { return true; } for (var i=0; i<ignore.length; i++){ if (item instanceof ignore[i]) { return true; } } return false; } else { return true; } } function infant(value){ return Array.isArray(value) ? [] : {}; } function decycleIntoForest(object, replacer) { if (typeof replacer !== 'function'){ replacer = function(x){ return x; } } object = replacer(object); if (primitive(object)) return object; var objects = [object]; var forest = [infant(object)]; var bucket = new WeakMap(); // bucket = inverse of objects bucket.set(object, 0); function addToBucket(obj){ var result = objects.length; objects.push(obj); bucket.set(obj, result); return result; } function isInBucket(obj){ return bucket.has(obj); } function processNode(source, target){ Object.keys(source).forEach(function(key){ var value = replacer(source[key]); if (primitive(value)){ target[key] = {value: value}; } else { var ptr; if (isInBucket(value)){ ptr = bucket.get(value); } else { ptr = addToBucket(value); var newTree = infant(value); forest.push(newTree); processNode(value, newTree); } target[key] = {pointer: ptr}; } }); } processNode(object, forest[0]); return forest; }; function deForestIntoCycle(forest) { var objects = []; var objectRequested = []; var todo = []; function processTree(idx) { if (idx in objects) return objects[idx]; if (objectRequested[idx]) return null; objectRequested[idx] = true; var tree = forest[idx]; var node = Array.isArray(tree) ? [] : {}; for (var key in tree) { var o = tree[key]; if ('pointer' in o) { var ptr = o.pointer; var value = processTree(ptr); if (value === null) { todo.push({ node: node, key: key, idx: ptr }); } else { node[key] = value; } } else { if ('value' in o) { node[key] = o.value; } else { throw new Error('unexpected') } } } objects[idx] = node; return node; } var result = processTree(0); for (var i = 0; i < todo.length; i++) { var item = todo[i]; item.node[item.key] = objects[item.idx]; } return result; }; var console = { log: function(x){ var the = document.getElementById('the'); the.textContent = the.textContent + '\n' + x; }, delimiter: function(){ var the = document.getElementById('the'); the.textContent = the.textContent + '\n*******************************************'; } } function logCyclicObjectToConsole(root) { var cycleFree = decycleIntoForest(root); var shown = cycleFree.map(function(tree, idx) { return false; }); var indentIncrement = 4; function showItem(nodeSlot, indent, label) { var leadingSpaces = ' '.repeat(indent); var leadingSpacesPlus = ' '.repeat(indent + indentIncrement); if (shown[nodeSlot]) { console.log(leadingSpaces + label + ' ... see above (object #' + nodeSlot + ')'); } else { console.log(leadingSpaces + label + ' object#' + nodeSlot); var tree = cycleFree[nodeSlot]; shown[nodeSlot] = true; Object.keys(tree).forEach(function(key) { var entry = tree[key]; if ('value' in entry) { console.log(leadingSpacesPlus + key + ": " + entry.value); } else { if ('pointer' in entry) { showItem(entry.pointer, indent + indentIncrement, key); } } }); } } console.delimiter(); showItem(0, 0, 'root'); }; function stringify(obj){ return JSON.stringify(decycleIntoForest(obj)); } function parse(str){ return deForestIntoCycle(JSON.parse(str)); } var CYCLICJSON = { decycleIntoForest: decycleIntoForest, deForestIntoCycle : deForestIntoCycle, logCyclicObjectToConsole: logCyclicObjectToConsole, stringify : stringify, parse : parse } function setObject(name, object){ var str = stringify(object); localStorage.setItem(name, str); } function getObject(name){ var str = localStorage.getItem(name); if (str===null) return null; return parse(str); } return { CYCLICJSON : CYCLICJSON, setObject : setObject, getObject : getObject } })(); obj = { L: { L: { v: 'lorem' }, R: { v: 'ipsum' } }, R: { L: { v: 'dolor' }, R: { L: { v: 'sit' }, R: { v: 'amet' } } } } obj.R.L.uncle = obj.L; obj.R.R.uncle = obj.L; obj.R.R.L.uncle = obj.R.L; obj.R.R.R.uncle = obj.R.L; obj.L.L.uncle = obj.R; obj.L.R.uncle = obj.R; // LOCALSTORAGE.setObject('latinUncles', obj) // recovered = LOCALSTORAGE.getObject('latinUncles') // localStorage not available inside fiddle ): LOCALSTORAGE.CYCLICJSON.logCyclicObjectToConsole(obj) putIntoLS = LOCALSTORAGE.CYCLICJSON.stringify(obj); recovered = LOCALSTORAGE.CYCLICJSON.parse(putIntoLS); LOCALSTORAGE.CYCLICJSON.logCyclicObjectToConsole(recovered); var the = document.getElementById('the'); the.textContent = the.textContent + '\n\n' + JSON.stringify( [ obj.L.L.v === recovered.L.L.v, obj.L.R.v === recovered.L.R.v, obj.R.L.v === recovered.R.L.v, obj.R.R.L.v === recovered.R.R.L.v, obj.R.R.R.v === recovered.R.R.R.v, obj.R.L.uncle === obj.L, obj.R.R.uncle === obj.L, obj.R.R.L.uncle === obj.R.L, obj.R.R.R.uncle === obj.R.L, obj.L.L.uncle === obj.R, obj.L.R.uncle === obj.R, recovered.R.L.uncle === recovered.L, recovered.R.R.uncle === recovered.L, recovered.R.R.L.uncle === recovered.R.L, recovered.R.R.R.uncle === recovered.R.L, recovered.L.L.uncle === recovered.R, recovered.L.R.uncle === recovered.R ] )<pre id='the'></pre>January 21, 2020 at 1:11 am #9152
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
David Hoang
KeymasterYou cannot store a key value without a string format.
LocalStorage only supports string formats for keys/values.
That is why you should convert your data to string whatever it is an array or object.
To store data in localStorage, first of all stringify it using the JSON.stringify() method.
var myObj = [{name:"test", time:"Date 2017-02-03T08:38:04.449Z"}]; localStorage.setItem('item', JSON.stringify(myObj));Then when you want to retrieve data, you need to parse the string to object again.
var getObj = JSON.parse(localStorage.getItem('item'));February 6, 2020 at 12:02 pm #9137
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
David Hoang
KeymasterlocalStorage.setItem('user', JSON.stringify(user));Then to retrieve it from the store and convert to an object again:
var user = JSON.parse(localStorage.getItem('user')); If we need to delete all entries of the store we can simply do: localStorage.clear();August 4, 2020 at 4:26 am #9142
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
David Hoang
KeymasterCircular References
In this answer I focus on data-only objects (without functions, etc.) with circular references and develop ideas mentioned by maja and mathheadinclouds (I use his test case and
my code is several times shorter).Actually, we can use JSON.stringify with a proper replacer – if the source object contains multi-references to some object, or contains circular references then we reference it by special path-string (similar to JSONPath).
// JSON.strigify replacer for objects with circ ref function refReplacer() { let m = new Map(), v = new Map(), init = null; return function(field, value) { let p = m.get(this) + (Array.isArray(this) ? `[${field}]` : '.' + field); let isComplex = value === Object(value) if (isComplex) m.set(value, p); let pp = v.get(value)||''; let path = p.replace(/undefined\.\.?/, ''); let val = pp ? `#REF:${pp[0] == '[' ? '$':'$.'}${pp}` : value; !init ? (init=value) : (val===init ? val="#REF:$" : 0); if(!pp && isComplex) v.set(value, path); return val; } } // --------------- // TEST // --------------- // Generate obj with duplicate/circular references let obj = { L: { L: { v: 'lorem' }, R: { v: 'ipsum' } }, R: { L: { v: 'dolor' }, R: { L: { v: 'sit' }, R: { v: 'amet' } } } } obj.R.L.uncle = obj.L; obj.R.R.uncle = obj.L; obj.R.R.L.uncle = obj.R.L; obj.R.R.R.uncle = obj.R.L; obj.L.L.uncle = obj.R; obj.L.R.uncle = obj.R; testObject = obj; let json = JSON.stringify(testObject, refReplacer(), 4); console.log("Test Object\n", testObject); console.log("JSON with JSONpath references\n", json);Parse such JSON content with JSONpath-like references:
// Parse JSON content with JSONpath references to object function parseRefJSON(json) { let objToPath = new Map(); let pathToObj = new Map(); let o = JSON.parse(json); let traverse = (parent, field) => { let obj = parent; let path = '#REF:$'; if (field !== undefined) { obj = parent[field]; path = objToPath.get(parent) + (Array.isArray(parent) ? `[${field}]` : `${field ? '.' + field : ''}`); } objToPath.set(obj, path); pathToObj.set(path, obj); let ref = pathToObj.get(obj); if (ref) parent[field] = ref; for (let f in obj) if (obj === Object(obj)) traverse(obj, f); } traverse(o); return o; } // --------------- // TEST 1 // --------------- let json = ` { "L": { "L": { "v": "lorem", "uncle": { "L": { "v": "dolor", "uncle": "#REF:$.L" }, "R": { "L": { "v": "sit", "uncle": "#REF:$.L.L.uncle.L" }, "R": { "v": "amet", "uncle": "#REF:$.L.L.uncle.L" }, "uncle": "#REF:$.L" } } }, "R": { "v": "ipsum", "uncle": "#REF:$.L.L.uncle" } }, "R": "#REF:$.L.L.uncle" }`; let testObject = parseRefJSON(json); console.log("Test Object\n", testObject); // --------------- // TEST 2 // --------------- console.log('Tests from mathheadinclouds answer: '); let recovered = testObject; let obj = { // Original object L: { L: { v: 'lorem' }, R: { v: 'ipsum' } }, R: { L: { v: 'dolor' }, R: { L: { v: 'sit' }, R: { v: 'amet' } } } } obj.R.L.uncle = obj.L; obj.R.R.uncle = obj.L; obj.R.R.L.uncle = obj.R.L; obj.R.R.R.uncle = obj.R.L; obj.L.L.uncle = obj.R; obj.L.R.uncle = obj.R; [ obj.L.L.v === recovered.L.L.v, obj.L.R.v === recovered.L.R.v, obj.R.L.v === recovered.R.L.v, obj.R.R.L.v === recovered.R.R.L.v, obj.R.R.R.v === recovered.R.R.R.v, obj.R.L.uncle === obj.L, obj.R.R.uncle === obj.L, obj.R.R.L.uncle === obj.R.L, obj.R.R.R.uncle === obj.R.L, obj.L.L.uncle === obj.R, obj.L.R.uncle === obj.R, recovered.R.L.uncle === recovered.L, recovered.R.R.uncle === recovered.L, recovered.R.R.L.uncle === recovered.R.L, recovered.R.R.R.uncle === recovered.R.L, recovered.L.L.uncle === recovered.R, recovered.L.R.uncle === recovered.R ].forEach(x => console.log('test pass: ' + x));To load/save the resulting JSON content into storage, use the following code:
localStorage.myObject = JSON.stringify(testObject, refReplacer()); // Save testObject = parseRefJSON(localStorage.myObject); // LoadMarch 19, 2021 at 5:43 am #9138
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
David Hoang
KeymasterI suggest using Jackson-js. It is a library that handles serializing and deserializing of Objects while retaining their structure, based on decorators.
The library handles all the pitfalls such as cyclic reference, attributes aliasing, etc.
Simply describe your class using the @JsonProperty() and @JsonClassType() decorators.
Serialize your object using:
const objectMapper = new ObjectMapper(); localstore.setItem(key, objectMapper.stringify<yourObjectType>(yourObject));For slightly more detailed explanation, check my answer here:
Typescript objects serialization?
And the Jackson-js tutorial here:
April 5, 2021 at 2:53 am #9143
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
David Hoang
KeymasterThis question has been answered sufficiently from the JavaScript-only perspective, and others have already noted that both
localStorage.getItemandlocalStorage.setItemhave no concept of objects—they handle strings and strings only. This answer provides a TypeScript-friendly solution that incorporates what others have suggested in JavaScript-only solutions.TypeScript 4.2.3
Storage.prototype.setObject = function (key: string, value: unknown) { this.setItem(key, JSON.stringify(value)); }; Storage.prototype.getObject = function (key: string) { const value = this.getItem(key); if (!value) { return null; } return JSON.parse(value); }; declare global { interface Storage { setObject: (key: string, value: unknown) => void; getObject: (key: string) => unknown; } }Usage
localStorage.setObject('ages', [23, 18, 33, 22, 58]); localStorage.getObject('ages');Explanation
We declare both
setObjectandgetObjectfunctions on theStorageprototype—localStorageis an instance of this type. There’s nothing special we really need to note besides the null handling ingetObject. SincegetItemcan returnnull, we must exit early since callingJSON.parseon anullvalue will throw a runtime exception.After declaring the functions on the
Storageprototype, we include their type definitions on theStoragetype in the global namespace.Note: If we defined these functions with arrow functions, we’d need to assume that the storage object we’re calling is always
localStorage, which might not be true. For instance, the above code will addsetObjectandgetObjectsupport tosessionStorageas well.December 17, 2021 at 1:33 am #9145
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
Deprecated: Function seems_utf8 is deprecated since version 6.9.0! Use wp_is_valid_utf8() instead. in /home/u337135316/domains/bzotech.com/public_html/wp-includes/functions.php on line 6131
David Hoang
KeymasterlocalStorage.setItem('obj',JSON.stringify({name:'Akash'})); // Set Object in localStorage localStorage.getItem('obj'); // Get Object from localStorage sessionStorage.setItem('obj',JSON.stringify({name:'Akash'})); // Set Object in sessionStorage sessionStorage.getItem('obj'); // Get Object from sessionStorage -
AuthorPosts
- You must be logged in to reply to this topic.
