1

Trying to accomplish:

The website is an online Bible; I'd like to allow users to do the following....

  1. Allow user to highlight (add yellow background to text) a verse by clicking on it. They can toggle the highlight on and off by clicking on it.

  2. Save the verse to local storage, so that when they come back to the page at a later time, the verses will remain highlighted.

Relevant code

Twig is the template engine I'm using. Each bible verse is generated with the following:

<span id="{{ result.verse }}" onclick="javascript:saveVerse('{{ result.verse }}'); highlighter('{{ result.verse }}')">
    <sup class="verse">{{ result.verse }}</sup> &nbsp;&nbsp; 
    <span>{{ result.text }}</span>
</span>

Here is an example of the generated HTML

<span id="1" onclick="javascript:saveVerse('1'); highlighter('1')" class="">
    <sup class="verse">1</sup> &nbsp;&nbsp; 
    <span id="verseText-1"> And the ark of the LORD was in the country of the Philistines seven months.</span>
</span>

What I've tried

#1 was simple enough. I have that working properly. When user clicks on the verse, it sends the <span> id to the highlighter() function, which just uses toggleClass() to add/remove some css. That issue is resolved.

#2 is where I'm stuck. The code I currently have is below:

function saveVerse( verse ) 
{    
    // Save to local storage
    let data = JSON.parse( localStorage.getItem("savedVerses") );

    var saveVerse = [{
      book: "{{ book }}",
      chapter: {{ chapter }},
      verse: verse
    }];

    $(data).push({saveVerse});

    localStorage.setItem("savedVerses", JSON.stringify( data ));
}

What I would like to do is store the data to local storage with the key name "savedVerses", and that key should keep track of the books, chapters and corresponding verses. For example, the :

savedVerses[0]:
    "book": 'Genesis',
    "chapter": 6,
    "verse": 21
savedVerses[1]:
    "book": 'Matthew',
    "chapter": 2,
    "verse": 14
savedVerses[2]:
    "book": 'Exodus',
    "chapter": 8,
    "verse": 10

and so on...

What actually happens is that when I look in the dev console, all I see is this:

{"book":"1 Samuel","chapter":6,"verse":"3"}

It appears to be saving the first verse clicked, but does not append any addition data to it.

Can anyone tell where I'm going wrong? Thank you in advance!

4
  • $(data) 👈 why are you wrapping this in a jQuery object?
    – Phil
    Commented Jun 13 at 4:02
  • @Phil If I don't, I get data.push() is not a function error Commented Jun 13 at 4:07
  • 1
    Which means data is not an array. Doesn't mean "wrap it in jQuery".
    – VLAZ
    Commented Jun 13 at 4:10
  • 1
    Looks like you've managed to add an object, not an array to localStorage. You'll want to clear that before trying my answer below
    – Phil
    Commented Jun 13 at 4:24

1 Answer 1

2

There's a couple of issues here.

$(data).push({saveVerse});

This is wrapping data in a jQuery object. Calling push() on it has no affect on data itself.

Also, the way you're constructing saveVerse and pushing it into the array would result in a structure like this which isn't what you want

[
  {
    "saveVerse": [
      {
        "book": "Genesis",
        "chapter": 6,
        "verse": 21
      }
    ]
  },
  ...
]

Here's what I'd do...

  1. Embed your data into the <span> tag. This will allow you to take advantage of Twig's HTML encoding

    <span
      class="verse"
      data-book="{{ book }}"
      data-chapter="{{ chapter }}"
      data-verse="{{ result.verse }}"
    >
    
  2. Add event listeners for your click events. In those, retrieve the array from localStorage and default it to an empty array if it doesn't exist. Then add your data pulled from the element itself.

    const STORAGE_KEY = 'savedVerses';
    
    $('.verse').on('click', function() {
      const { book, chapter, verse } = $(this).data();
    
      const data = JSON.parse(localStorage.getItem(STORAGE_KEY)) ?? [];
      data.push({ book, chapter, verse });
      localStorage.setItem(STORAGE_KEY, JSON.stringify(data));
    
      // and call highlighter
      highlighter(verse);
    });
    
0

Not the answer you're looking for? Browse other questions tagged or ask your own question.