Search code examples
javascriptjsongoogle-chrome-devtools

Can't see localStorage key val pairs in Chrome Dev Tools


I have a json file that stores data which is displayed on my page using javascript. This json file and its key val pairs are not visible or accessible in Chrome's Dev Tools. This component manages json files:

/**
 * Takes a filename and a JS object and initiates a download through the browser
 * @param {String} filename
 * @param {any} object JSON serializable object
 * @return {undefined}
 */
export const downloadJson = (filename, object) => {
  const content = JSON.stringify(object, null, 2);
  const el = document.createElement('a');
  el.setAttribute('href', `data:application/json;charset=utf-8,${encodeURIComponent(content)}`);
  el.setAttribute('download', filename);
  el.hidden = true;
  document.body.appendChild(el);
  el.click();
  document.body.removeChild(el);
};

/**
 * Gets the `target.result` property from an event, or returns null
 * if it fails at any point
 * @type {Function}
 * @param {Event} event load Event
 * @return {File}
 */
const getFileResult = propPathOr(null, ['target', 'result']);

/**
 * Takes a file and reads it as JSON, resolving the JSON-parsed
 * file contents
 * @param {File} file
 * @return {Promise<[Object]>} Returns Promise of Array of Archive Entries
 */
export const readFileAsJson = file => {
  const reader = new FileReader();
  const promise = new Promise((resolve, reject) => {
    reader.onload = compose(resolve, JSON.parse, getFileResult);
    reader.onerror = reject;
  });
  reader.readAsText(file);
  return promise;
};

export const readFileListAsJson = files =>
  Promise.all(
    Array.from(files)
      .map(readFileAsJson)
  )
    .catch(console.error);

This is the database component:

// DATABASE functions
import { get, set, keys } from 'idb-keyval';
import { sha1 } from './hash.js';

const getKey = key => get(key);

export const getAllEntries = async () =>
  await Promise.all((await keys()).map(getKey));

export const writeMultipleEntries = entries =>
  entries.forEach(writeSingleEntry);

/**
 * @typedef {Object} ArchiveEntry
 * @property {String} date
 * @property {String} passage
 * @property {String} question
 * @property {String} answer
 */

/**
 * Writes a single archive entry to idb
 * @param {ArchiveEntry} entry
 * @return {ArchiveEntry}
 */
export const writeSingleEntry = async ({ date, passage, question, answer }) => {
  const hash = await hashEntry({ date, passage, question });
  await set(hash, { date, passage, question, answer });
  return { date, passage, question, answer };
};

/**
 * Generates a hash of an entry to use as it's idb key
 * @param {ArchiveEntry} entry
 * @return {string}
 */
const hashEntry = ({ date, passage, question }) =>
  sha1(`${date}-${passage}-${question}`);

Values are stored using this function:

const updateDb =
  ({ passage, question }) =>
  (answer) =>
    writeSingleEntry({ date: new Date(), answer, passage, question });

Storage is handled by its own script:

export const storeOnInput = key => ({ target: { value } }) => writeValue(key, value);
export const readValue = key => localStorage.getItem(key);
export const writeValue = (key, val) => localStorage.setItem(key, val);

It is called in several components. Here to write and read the value of a text passage:

onActiveChanged(active) {
  this.passage = readValue('passage-input');
}   

onKeyup(event) {
    writeValue('passage-input', event.target.value);
}

Here to write and record a question:

onActiveChanged(active) {
  this.question = readValue("question-input");
  this.passage = readValue("passage-input");
}

onKeyup(event) {
   writeValue("question-input", event.target.value);
}

Here to provide an answer and reset the form:

const answer = document.getElementById('answer');
const write = document.getElementById('write');
const question = document.getElementById('question');

const onAnswerSubmitted = ({ detail: answer }) => {
  writeValue('answer', answer);
};

onActiveChanged(active) {
  if (!active) return;
  this.answer = readValue('answer');
}

resetQuestion() {
  this.dispatchEvent(new CustomEvent('reset-question'));
  writeValue('question-input', '');
  writeValue('answer', '');
}

resetWrite() {
  this.resetQuestion();
  this.dispatchEvent(new CustomEvent('reset-passage'));
  writeValue('passage-input', '');
}

Here to get entries:

  onActiveChanged(active) {
    if (active) this.getEntries();
  }

 async getEntries() {
    this.entries = await getAllEntries();
    this.entry = new URLSearchParams(location.search.substring(1)).get("date");
    console.log("here are the dates: \n", prettyDate(this.entries[0].date));
    console.log("here is an answer: \n", this.entries[0].answer);
  }

Here to download and upload the JSON file:

  async exportBackup() {
    downloadJson(`backup ${new Date()}.json`, await getAllEntries());
  }

  async importBackup({ target: { files } }) {
    return readFileListAsJson(files)
      .then(map(writeMultipleEntries));
  }

Unlike this question, nothing is showing in Storage > Local Storage, and it is not a Chrome UI design flaw issue. Image of Dev Tools Local Storage panel

It is possible to confirm the values have been written and are are accessible from the json file using functions like:

console.log(this.entries[0].date)
console.log(this.entries[0].answer)

but I would like to be able to debug by viewing the entire json file.


Solution

  • I had the same problem today while working on my webapp :

    • I could access some data i registered on the localstorage via the console (JSON.parse(localStorage["my-storage-key"])
    • But in the Chrome dev tools, in the Application tab, the https://localhost:4200 entry was totaly empty, just like in the screen capture you provided.

    What fixed the problem for me was to click "Restore defaults and reload" in the preferences of the chrome DevTools, and i could see the entries in the table again.

    Restore defaults and reload button in the chrome devtools preferences panel