<!-- @license Copyright (c) 2015 The Polymer Project Authors. All rights reserved. This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as part of the polymer project is also subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt --> <link rel="import" href="../polymer/polymer.html"> <!-- Element access to Web Storage API (window.localStorage). Keeps `value` property in sync with localStorage. Value is saved as json by default. ###Usage: `ls-sample` will automatically save changes to its value. <dom-module id="ls-sample"> <iron-localstorage name="my-app-storage" value="{{cartoon}}" on-iron-localstorage-load-empty="initializeDefaultCartoon" ></iron-localstorage> </dom-module> <script> Polymer({ is: 'ls-sample', properties: { cartoon: { type: Object } }, // initializes default if nothing has been stored initializeDefaultCartoon: function() { this.cartoon = { name: "Mickey", hasEars: true } }, // use path set api to propagate changes to localstorage makeModifications: function() { this.set('cartoon.name', "Minions"); this.set('cartoon.hasEars', false); } }); </script> ###Tech notes: * * `value.*` is observed, and saved on modifications. You must use property notification methods to modify value for changes to be observed. * * Set `auto-save-disabled` to prevent automatic saving. * * Value is saved as JSON by default. * * To delete a key, set value to null * Element listens to StorageAPI `storage` event, and will reload upon receiving it. * **Warning**: do not bind value to sub-properties until Polymer [bug 1550](https://github.com/Polymer/polymer/issues/1550) is resolved. Local storage will be blown away. `<iron-localstorage value="{{foo.bar}}"` will cause **data loss**. @demo demo/index.html @hero hero.svg --> <dom-module id="iron-localstorage"></dom-module> <script> Polymer({ is: 'iron-localstorage', properties: { /** * localStorage item key */ name: { type: String, value: '' }, /** * The data associated with this storage. * If set to null item will be deleted. * @type {*} */ value: { type: Object, notify: true }, /** * If true: do not convert value to JSON on save/load */ useRaw: { type: Boolean, value: false }, /** * Value will not be saved automatically if true. You'll have to do it manually with `save()` */ autoSaveDisabled: { type: Boolean, value: false }, /** * Last error encountered while saving/loading items */ errorMessage: { type: String, notify: true }, /** True if value has been loaded */ _loaded: { type: Boolean, value: false } }, observers: [ '_debounceReload(name,useRaw)', '_trySaveValue(autoSaveDisabled)', '_trySaveValue(value.*)' ], ready: function() { this._boundHandleStorage = this._handleStorage.bind(this); }, attached: function() { window.addEventListener('storage', this._boundHandleStorage); }, detached: function() { window.removeEventListener('storage', this._boundHandleStorage); }, _handleStorage: function(ev) { if (ev.key == this.name) { this._load(true); } }, _trySaveValue: function() { if (this._doNotSave) { return; } if (this._loaded && !this.autoSaveDisabled) { this.debounce('save', this.save); } }, _debounceReload: function() { this.debounce('reload', this.reload); }, /** * Loads the value again. Use if you modify * localStorage using DOM calls, and want to * keep this element in sync. */ reload: function() { this._loaded = false; this._load(); }, /** * loads value from local storage * @param {boolean=} externalChange true if loading changes from a different window */ _load: function(externalChange) { var v = window.localStorage.getItem(this.name); if (v === null) { this._loaded = true; this._doNotSave = true; // guard for save watchers this.value = null; this._doNotSave = false; this.fire('iron-localstorage-load-empty', { externalChange: externalChange}); } else { if (!this.useRaw) { try { // parse value as JSON v = JSON.parse(v); } catch(x) { this.errorMessage = "Could not parse local storage value"; console.error("could not parse local storage value", v); v = null; } } this._loaded = true; this._doNotSave = true; this.value = v; this._doNotSave = false; this.fire('iron-localstorage-load', { externalChange: externalChange}); } }, /** * Saves the value to localStorage. Call to save if autoSaveDisabled is set. * If `value` is null, deletes localStorage. */ save: function() { var v = this.useRaw ? this.value : JSON.stringify(this.value); try { if (this.value === null) { window.localStorage.removeItem(this.name); } else { window.localStorage.setItem(this.name, /** @type {string} */ (v)); } } catch(ex) { // Happens in Safari incognito mode, this.errorMessage = ex.message; console.error("localStorage could not be saved. Safari incoginito mode?", ex); } } /** * Fired when value loads from localStorage. * * @event iron-localstorage-load * @param {{externalChange:boolean}} detail - * externalChange: true if change occured in different window. */ /** * Fired when loaded value does not exist. * Event handler can be used to initialize default value. * * @event iron-localstorage-load-empty * @param {{externalChange:boolean}} detail - * externalChange: true if change occured in different window. */ }); </script>