Storage
Simple, prefixed localStorage with auto-serialisation and model persistence.
Basic Operations
Store and retrieve data with automatic JSON serialisation. All keys are prefixed with domma: to avoid collisions.
get()
set()
remove()
has()
clear()
keys()
getAll()
setAll()
size()
totalSize()
isAvailable()
// Set values (auto-stringify)
S.set('user', { name: 'Alice', role: 'admin' });
S.set('preferences', ['dark', 'compact']);
S.set('count', 42);
// Get values (auto-parse)
S.get('user'); // { name: 'Alice', role: 'admin' }
S.get('preferences'); // ['dark', 'compact']
S.get('missing', []); // Default value if not found
// Check and manage
S.has('user'); // true
S.keys(); // ['user', 'preferences', 'count']
S.remove('count');
S.clear(); // Clear only Domma keys
Click a button to see result
<div class="grid grid-cols-2 gap-4">
<div>
<div class="form-group">
<label>Key</label>
<input type="text" id="storage-key" class="form-input" value="test-key">
</div>
<div class="form-group">
<label>Value (JSON)</label>
<textarea id="storage-value" class="form-input" rows="3">{"message": "Hello, Domma!"}</textarea>
</div>
<div class="flex gap-2">
<button type="button" class="btn btn-primary" id="btn-set">Set</button>
<button type="button" class="btn btn-secondary" id="btn-get">Get</button>
<button type="button" class="btn btn-outline" id="btn-remove">Remove</button>
<button type="button" class="btn btn-danger" id="btn-clear">Clear All</button>
</div>
</div>
<div>
<label class="font-semibold mb-2 block">Result</label>
<div class="storage-demo-result" id="storage-result">Click a button to see result</div>
</div>
</div>/**
* Try It - from public/showcase/storage.
*/
export function mount(root) {
const pageRoot = $(root).closest('.sx-showcase').get(0) || root;
// ============================================
// Basic Storage Demo
// ============================================
const $result = $(root).find('#storage-result');
function showResult(data) {
$result.text(JSON.stringify(data, null, 2));
}
$(root).find('#btn-set').on('click', function () {
const key = $(root).find('#storage-key').val();
let value;
try {
value = JSON.parse($(root).find('#storage-value').val());
} catch (e) {
value = $(root).find('#storage-value').val();
}
const success = S.set(key, value);
showResult({action: 'set', key, success, value});
refreshInspector();
});
$(root).find('#btn-get').on('click', function () {
const key = $(root).find('#storage-key').val();
const value = S.get(key, null);
showResult({action: 'get', key, value, found: value !== null});
});
$(root).find('#btn-remove').on('click', function () {
const key = $(root).find('#storage-key').val();
const success = S.remove(key);
showResult({action: 'remove', key, success});
refreshInspector();
});
$(root).find('#btn-clear').on('click', function () {
const count = S.clear();
showResult({action: 'clear', keysCleared: count});
refreshInspector();
updatePrefsDisplay();
});
// ============================================
// Model Persistence Demo
// ============================================
const prefsModel = M.create({
theme: {type: 'string', default: 'light'},
fontSize: {type: 'number', default: 14, min: 10, max: 24},
notifications: {type: 'boolean', default: true}
}, {}, {persist: 'demo-prefs'});
function updatePrefsDisplay() {
const data = prefsModel.toJSON();
$(pageRoot).find('#prefs-state').text(JSON.stringify(data, null, 2));
// Update form inputs to match model
$(pageRoot).find('#pref-theme').val(data.theme);
$(pageRoot).find('#pref-fontsize').val(data.fontSize);
$(pageRoot).find('#pref-notifications').val(String(data.notifications));
}
// ============================================
// Storage Inspector
// ============================================
function formatBytes(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}
function refreshInspector() {
const keys = S.keys();
const totalSize = S.totalSize();
const available = S.isAvailable();
// Update stats
$(pageRoot).find('#stat-keys').text(keys.length);
$(pageRoot).find('#stat-size').text(formatBytes(totalSize));
$(pageRoot).find('#stat-available').text(available ? 'Yes' : 'No');
// Update inspector
const $inspector = $(pageRoot).find('#storage-inspector');
if (keys.length === 0) {
$inspector.html('<p class="text-muted">No data stored</p>');
return;
}
let html = '';
keys.forEach(key => {
const value = S.get(key);
const displayValue = JSON.stringify(value);
html += `
<div class="storage-item-style">
<span class="storage-key-style">${_.escape(key)}</span>
<span class="storage-value-style">${_.escape(displayValue)}</span>
</div>
`;
});
$inspector.html(html);
}
}Model Persistence
Models can automatically persist to localStorage. Data is saved on every change and restored when the model is created.
// Create a persistent model
const settings = M.create({
theme: { type: 'string', default: 'light' },
fontSize: { type: 'number', default: 14 },
notifications: { type: 'boolean', default: true }
}, {}, { persist: 'app-settings' });
// Changes auto-save to localStorage
settings.set('theme', 'dark');
settings.set('fontSize', 16);
// On page reload, data is automatically restored!
// Manual control
settings.save(); // Force save
settings.load(); // Force reload from storage
settings.clearStorage(); // Remove from localStorage
settings.reset(true); // Reset and clear storage
Change these settings and refresh the page - they'll persist!
Loading...
<p class="text-muted mb-4">Change these settings and refresh the page - they'll persist!</p>
<div class="grid grid-cols-3 gap-4 mb-4">
<div class="form-group">
<label>Theme</label>
<select id="pref-theme" class="form-select">
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
</div>
<div class="form-group">
<label>Font Size</label>
<input type="number" id="pref-fontsize" class="form-input" min="10" max="24" value="14">
</div>
<div class="form-group">
<label>Notifications</label>
<select id="pref-notifications" class="form-select">
<option value="true">Enabled</option>
<option value="false">Disabled</option>
</select>
</div>
</div>
<div class="flex gap-2">
<button type="button" class="btn btn-outline" id="btn-reset-prefs">Reset to Defaults</button>
<button type="button" class="btn btn-danger btn-sm" id="btn-clear-prefs">Clear Storage</button>
</div>
<div class="storage-demo-result mt-4" id="prefs-state">Loading...</div>/**
* Persistent Settings - from public/showcase/storage.
*/
export function mount(root) {
const pageRoot = $(root).closest('.sx-showcase').get(0) || root;
// ============================================
// Model Persistence Demo
// ============================================
const prefsModel = M.create({
theme: {type: 'string', default: 'light'},
fontSize: {type: 'number', default: 14, min: 10, max: 24},
notifications: {type: 'boolean', default: true}
}, {}, {persist: 'demo-prefs'});
function updatePrefsDisplay() {
const data = prefsModel.toJSON();
$(root).find('#prefs-state').text(JSON.stringify(data, null, 2));
// Update form inputs to match model
$(root).find('#pref-theme').val(data.theme);
$(root).find('#pref-fontsize').val(data.fontSize);
$(root).find('#pref-notifications').val(String(data.notifications));
}
// Bind form inputs to model
$(root).find('#pref-theme').on('change', function () {
prefsModel.set('theme', $(this).val());
updatePrefsDisplay();
refreshInspector();
});
$(root).find('#pref-fontsize').on('input', function () {
const val = parseInt($(this).val(), 10);
if (val >= 10 && val <= 24) {
prefsModel.set('fontSize', val);
updatePrefsDisplay();
refreshInspector();
}
});
$(root).find('#pref-notifications').on('change', function () {
prefsModel.set('notifications', $(this).val() === 'true');
updatePrefsDisplay();
refreshInspector();
});
$(root).find('#btn-reset-prefs').on('click', function () {
prefsModel.reset();
updatePrefsDisplay();
refreshInspector();
});
$(root).find('#btn-clear-prefs').on('click', function () {
prefsModel.reset(true);
updatePrefsDisplay();
refreshInspector();
});
// Initial display
updatePrefsDisplay();
// ============================================
// Storage Inspector
// ============================================
function formatBytes(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}
function refreshInspector() {
const keys = S.keys();
const totalSize = S.totalSize();
const available = S.isAvailable();
// Update stats
$(pageRoot).find('#stat-keys').text(keys.length);
$(pageRoot).find('#stat-size').text(formatBytes(totalSize));
$(pageRoot).find('#stat-available').text(available ? 'Yes' : 'No');
// Update inspector
const $inspector = $(pageRoot).find('#storage-inspector');
if (keys.length === 0) {
$inspector.html('<p class="text-muted">No data stored</p>');
return;
}
let html = '';
keys.forEach(key => {
const value = S.get(key);
const displayValue = JSON.stringify(value);
html += `
<div class="storage-item-style">
<span class="storage-key-style">${_.escape(key)}</span>
<span class="storage-value-style">${_.escape(displayValue)}</span>
</div>
`;
});
$inspector.html(html);
}
}Storage Inspector
View all Domma storage keys in real-time.
0
Keys
0 B
Total Size
-
Available
No data stored
<div class="storage-stat-card">
<div class="storage-stat-value" id="stat-keys">0</div>
<div class="storage-stat-label">Keys</div>
</div>
<div class="storage-stat-card">
<div class="storage-stat-value" id="stat-size">0 B</div>
<div class="storage-stat-label">Total Size</div>
</div>
<div class="storage-stat-card">
<div class="storage-stat-value" id="stat-available">-</div>
<div class="storage-stat-label">Available</div>
</div>
<span class="font-semibold">Stored Data</span>
<button type="button" class="btn btn-outline btn-sm" id="btn-refresh-inspector">Refresh</button>
<div class="storage-inspector-style" id="storage-inspector">
<p class="text-muted">No data stored</p>
</div>/**
* Storage Inspector - from public/showcase/storage.
*/
export function mount(root) {
// ============================================
// Storage Inspector
// ============================================
function formatBytes(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
}
function refreshInspector() {
const keys = S.keys();
const totalSize = S.totalSize();
const available = S.isAvailable();
// Update stats
$(root).find('#stat-keys').text(keys.length);
$(root).find('#stat-size').text(formatBytes(totalSize));
$(root).find('#stat-available').text(available ? 'Yes' : 'No');
// Update inspector
const $inspector = $(root).find('#storage-inspector');
if (keys.length === 0) {
$inspector.html('<p class="text-muted">No data stored</p>');
return;
}
let html = '';
keys.forEach(key => {
const value = S.get(key);
const displayValue = JSON.stringify(value);
html += `
<div class="storage-item-style">
<span class="storage-key-style">${_.escape(key)}</span>
<span class="storage-value-style">${_.escape(displayValue)}</span>
</div>
`;
});
$inspector.html(html);
}
$(root).find('#btn-refresh-inspector').on('click', refreshInspector);
// Initial inspector load
refreshInspector();
}Method Reference
Core Methods
| get(key, default) | Retrieve and auto-parse a value. Returns default if not found. |
|---|---|
| set(key, value) | Store a value with auto-stringify. Returns true if successful. |
| remove(key) | Remove a key from storage. |
| has(key) | Check if a key exists. |
| clear() | Clear all Domma-prefixed keys. Returns count of cleared keys. |
| keys() | List all Domma keys (without prefix). |
Utility Methods
| getAll() | Get all stored data as an object. |
|---|---|
| setAll(data) | Set multiple values at once from an object. |
| size(key) | Get size of a stored value in bytes. |
| totalSize() | Get total size of all Domma storage in bytes. |
isAvailable() |
Check if localStorage is available. |
Model Persistence Methods
| model.save() | Manually save model to localStorage. |
|---|---|
| model.load() | Manually load model from localStorage. |
| model.clearStorage() | Remove model data from localStorage. |
| model.isPersisted() | Check if model has persistence enabled. |
| model.getPersistKey() | Get the persistence key. |
| model.reset(true) | Reset model and clear storage. |