0

I cannot get the user input to push to Local Storage. When my quizData variable is an empty array it works fine,

let quizData = JSON.parse(localStorage.getItem('MyQuiz'));

and changing it back to this works because (I assume) there is already info in LS,

let quizData = JSON.parse(localStorage.getItem('MyQuiz'));

but clearing LS will cause it to fail again. Any help I can get would be greatly appreciated

let quizData = JSON.parse(localStorage.getItem('MyQuiz'));
const addQuiz = (ev) => {
  ev.preventDefault();

  let quizForm = {
    question: document.getElementById('question-input').value,
    a: document.getElementById('a-input').value,
    b: document.getElementById('b-input').value,
    c: document.getElementById('c-input').value,
    d: document.getElementById('d-input').value,
    correct: document.getElementById('correct-input').value,
  };

  quizData.push(quizForm);
  document.forms[0].reset();

  console.warn('added', { quizData });

  localStorage.setItem('MyQuiz', JSON.stringify(quizData));
};
document.addEventListener('DOMContentLoaded', () => {
  document.getElementById('submitForm').addEventListener('click', addQuiz);
  console.log(quizData);
});

and the error custom-questions.js:26

Uncaught TypeError: Cannot read properties of null (reading 'push') at HTMLButtonElement.addQuiz

John Swan
  • 1
  • 1
  • 1
    you need to retrieve within the handler, just accessing local storage once before declaring the listener is not adequate. Every time you set local storage it is a new JSON string, which will need to be retrieved and parsed on every `addQuiz` call. It's **not** a consistent array reference that can be held and pushed to. – pilchard Dec 26 '21 at 11:42

2 Answers2

1

You can simply set the quizData to a new array if there's nothing in the localStorage.

let quizData = JSON.parse(localStorage.getItem('MyQuiz')) ?? [];

If quizData is updated elsewhere, it is better to retrieve the latest array before updating it. So you can get the latest quizData inside addQuiz.

const addQuiz = (ev) => {
  ev.preventDefault();

  let quizForm = {
    question: document.getElementById('question-input').value,
    a: document.getElementById('a-input').value,
    b: document.getElementById('b-input').value,
    c: document.getElementById('c-input').value,
    d: document.getElementById('d-input').value,
    correct: document.getElementById('correct-input').value,
  };
  
  const quizData = JSON.parse(localStorage.getItem('MyQuiz')) ?? [];

  quizData.push(quizForm);
  document.forms[0].reset();

  console.warn('added', { quizData });

  localStorage.setItem('MyQuiz', JSON.stringify(quizData));
};
Ramesh Reddy
  • 10,159
  • 3
  • 17
  • 32
  • @pilchard That's true. Updated the answer – Ramesh Reddy Dec 26 '21 at 11:49
  • Definitely more robust – pilchard Dec 26 '21 at 11:53
  • @pilchard Actually, `localStorage` doesn't have to be retrieved every time. `quizData` is an array that gets mutated on every `addQuiz` call and `MyQuiz` is set to the updated array. So, `quizData` always refers to the updated array. – Ramesh Reddy Dec 26 '21 at 12:05
  • 1
    I understand that, and it overwrites localstorage everytime. If that one reference is the only place it's ever edited it's fine, and even more efficient than parsing every time. Also, multiple tab support... [Is localStorage thread safe?](https://stackoverflow.com/questions/22001112/is-localstorage-thread-safe) – pilchard Dec 26 '21 at 12:07
0

You should initialize quizData as empty array if null or undefined.

let quizData = JSON.parse(localStorage.getItem('MyQuiz')) || [];
Max G.
  • 733
  • 3
  • 10