Vue.JS encounter a hiccup while attempting to store data in the local storage

My application is set up to fetch data from a rest api, and it consists of two key components:

1 - (main) Display the results 2 - (list) To display a list of selected items from the main results

The feature I am trying to implement involves adding a save button to the list(2) component. This button will allow users to save a selected list of items from the api. However, I encountered an error which states:

Error in mounted hook: "SyntaxError: Unexpected token u in JSON at position 0"

List component

    <template>
      <div class="mb-5 mt-5 container">
        <div class="list-group">
          <a href="#" class="list-group-item list-group-item-action active">
            My List
            <span class="badge badge-light">{{List.length}}</span>
          </a>
          <a
            href="#"
            class="list-group-item list-group-item-action"
            v-for="(result, index) in List"
            :key="index"
          >
            {{result.collectionName}}
            <br>
            <b>{{result.artistName}}</b>
            <br>
            <div class="row">
              <div class="col-md-6">
                <button
                  class="btn btn-success btn-sm btn-block"
                  v-on:click="removeElement(index)"
                >Remove</button>
              </div>
              <div class="col-md-6">
                <button
                  class="btn btn-info btn-sm btn-block"
                  @click="toAlbum(result)"
                >View on iTunes</button>
              </div>
            </div>
          </a>
        </div>
        <button class="btn btn-info mt-5 btn-lg btn-block" @click="saveList()">Save</button>
      </div>
    </template>
    <script>
    export default {
      name: "List",
      props: ["List"],
      mounted() {
    if(localStorage.result) this.result = JSON.parse(this.result);
  },

      methods: {
          saveList() {
          localStorage.result = this.result;
          localStorage.setItem('result', JSON.stringify(this.result));   
          /* eslint-disable no-console */
          console.log(localStorage.result.length + 'List Saved');
          /* eslint-disable no-console */
        },
        removeElement: function(index) {
          this.List.splice(index, 1);
        },
        resizeArtworkUrl(result) {
          return result.artworkUrl100.replace("100x100", "160x160");
        },
        toiAlbum(result) {
          window.open(result.collectionViewUrl, "_blank");
        }
      }
    };
    </script>
    <style scoped>
    .album-cover {
      width: 100%;
      height: auto;
      background-color: aqua;
    }
    .album-container {
      height: 350px;
    }
    </style>

Main component

<template>
      <div class="container search">
        <div class="row">
          <div class="col-md-8">
     <div class="jumbotron mt-5" style="clear:both">
          <h1 class="display-4">{{title}}</h1>
          <p class="lead">{{intro}}</p>
          <hr class="my-4">
          <p v-if="validated" :class="errorTextClass">Enter a valid search term</p>
          <button
            type="button"
            class="btn btn-primary btn-lg mb-3"
            v-on:click="refreshPage"
            v-if="result.length > 1"
          >
            <font-awesome-icon icon="redo"/> Start again
          </button>
          <input
            class="form-control form-control-lg mb-3"
            type="search"
            placeholder="Search"
            aria-label="Search"
            v-model="search"
            required
            autocomplete="off"
            id="search"
          >
          <div v-for="(result, index) in result" :key="index">
            <div class="media mb-4">
              <img
                :src="resizeArtworkUrl(result)"
                alt="Album Cover"
                class="album-cover align-self-start mr-3"
              >
              <div class="media-body">
                <h4 class="mt-0">
                  <button
                    type="button"
                    class="btn btn-primary btn-lg mb-3 float-right"
                    v-on:click="addItem(result)"
                    :disabled="result.disableButton"
                  >
                    <font-awesome-icon icon="plus"/>
                  </button>
                  <b>{{result.collectionName}}</b>
                </h4>
                <h6 class="mt-0">{{result.artistName}}</h6>
                <p class="mt-0">{{result.primaryGenreName}}</p>
              </div>
            </div>
          </div>
          <div :class="loadingClass" v-if="loading"></div>
          <button
            class="btn btn-success btn-lg btn-block mb-3"
            type="submit"
            v-on:click="getData"
            v-if="result.length < 1"
          >
            <font-awesome-icon icon="search"/>Search
          </button>
        </div>
          </div>
          <div class="col-md-4">
        <List :List="List"/>

          </div>
        </div>
        <!-- <div class='div' v-bind:class="[isActive ? 'red' : 'blue']" @click="toggleClass()"></div> -->

      </div>
    </template>
    <script>
    import List from "../components/myList.vue";
    export default {
      name: "Hero",
      components: {
        List
      },
      data: function() {
        return {
          title: "Simple Search",
          isActive: true,
          intro: "This is a simple hero unit, a simple jumbotron-style.",
          subintro:
            "It uses utility classes for typography and spacing to space content out.",
          result: [],
          errors: [],
          List: [],
          search: "",
          loading: "",
          message: false,
          isValidationAllowed: false,
          loadingClass: "loading",
          errorTextClass: "error-text",
          disableButton: false
        };
      },
      watch: {
        search: function(val) {
          if (!val) {
            this.result = [];
          }
        }
      },
      computed: {
        validated() {
          return this.isValidationAllowed && !this.search;
        },
        isDisabled: function() {
          return !this.terms;
        }
      },
      methods: {
        
         // methods removed for brevity

      }
    };
    </script>
    <style>
    .loading {
      background-image: url("../assets/Rolling-1s-42px.gif");
      background-repeat: no-repeat;
      height: 50px;
      width: 50px;
      margin: 15px;
      margin-left: auto;
      margin-right: auto;
    }
    .error-text {
      color: red;
    }
    .media {
      text-align: left;
    }
    .album-cover {
      width: 80px;
      height: auto;
    }
    .red {
      background: red;
    }
    .blue {
      background: blue;
    }
    .div {
      width: 100px;
      height: 100px;
      display: inline-block;
      border: 1px solid black;
    }
    </style>

If you have any insights or suggestions regarding my setup, especially the use of local storage in the list component instead of the main component, please let me know. Your feedback is highly appreciated!

Answer №1

If you are performing JSON.parse(undefined), it will result in an Error being thrown. It is recommended to enclose this operation within a try/catch block to handle such scenarios:

function willThrow() {
  JSON.parse(undefined); 
}

// Vs.

function willCatch() {
  try {
    JSON.parse(undefined);
  } catch (err) {
    console.log(err);
  }
}

Take a look at the code snippet below (note that the following code won't actually execute due to Same Origin Policy issues related to localStorage):

const app = new Vue({
  el: "#app",
  data() {
    return {
      result: ""
    };
  },
  mounted() {
    
    try {
      if (localStorage.result) this.result = JSON.parse(this.result);
    } catch (err) {
      console.error(err);
    }
  }
});
<script src="https://unpkg.com/vue"></script>

<div id="app">{{result}}</div>

Answer №2

It seems like there is an attempt to parse something that does not exist in the current context.

When looking at your mounted hook, it appears:

if(localStorage.data) this.data = JSON.parse(this.data);

Perhaps you should consider using:

if(localStorage.data) this.data = JSON.parse(localStorage.data);

since this.data might be undefined initially

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Leveraging Webworkers in an Angular application for efficient data caching with service workers in the Angular-CLI

I am looking to run a function in the background using a worker, with data coming from an HTTP request. Currently, I have a mock calculation (e.data[0] * e.data[1] * xhrData.arr[3]) in place, but I plan to replace it with a function that returns the actual ...

An error of '______ is not defined' was thrown, I'm puzzled as to why

I keep encountering an error that says "weekday is not defined". I'm unsure of the reason behind this issue. Any assistance would be greatly appreciated! (function(exports) { var days = ["monday", "tuesday", "wednesday", "thursday"]; exports. ...

How to turn off and on all elements within a Div tag

Is there a way to disable all elements within a Div tag? I've managed to disable input types successfully, but I'm struggling with links. I attempted the solution provided here, but it didn't work. Here's the code snippet that worked f ...

What is the method to verify if a pop-up browser window has completed its loading process?

There is a link on my website that opens a new window. However, sometimes the new window takes so long to load. To prevent users from clicking on the link before the new window finishes loading, I want to disable it until then. I am aware that one way to ...

The Ajax call was successful but the callback function failed to return

I've been encountering some challenges with a small application I'm developing. After successfully setting it up to automatically populate one field with the same value entered in another field, I decided to integrate an AJAX request into the scr ...

Efficient PHP caching solution for optimizing JavaScript and CSS performance

I'm facing a unique challenge that I can't seem to solve through typical Google searches. I'm in the process of consolidating all my javascript and css into separate php files using require_once() to pull in the content. The structure of my ...

Tips for sending JSON data to the line chart function

Creating a line chart using Highcharts involves retrieving values from a database and passing those values to the line chart. Here is an example: //categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun ...

Having trouble displaying a table accurately in React

My goal is to create a table with Material UI in React, similar to the one shown in this image: https://i.stack.imgur.com/QIV8o.png Below is the code I have written so far for this table: return ( <> <div className="main-wrapper& ...

Embed a static label inside an input field that remains constant even while text is inputted, without using a placeholder. Crafted using HTML,

Take a look at the screenshot below - what you see on the left side is my current setup, while on the right side is the desired outcome achieved without any plugins or HTML5 attributes The left side scenario occurs when I have 2 input fields - one with th ...

How can I accommodate pushState routes from Backbone.js on a node.js express server?

pushState feature was added to Backbone.js in version 0.5. According to the backbone documentation: When using real URLs, your web server must be capable of rendering those pages as well. For example, if you have a route like /documents/100, your web s ...

The CssDependency dependency type in vue-cli@3 does not have any module factory available

After using vue-cli@3 to npm run build The system showed an error message: No module factory available for dependency type: CssDependency I have extensively searched for related solutions, but they all pertain to Angular. I also attempted the following ...

Resolving a CSS Layout Dilemma: How to Overlay Sidebar on Wrappers

I've run into a challenge while attempting to position a sidebar over page wrappers. The issue with absolute positioning arises when the sidebar needs to align with the corner of the blue header. I have contemplated using JavaScript to maintain its cu ...

Multer is not recognizing the uploaded file and is returning req.file

This question has definitely been asked multiple times in the past, and I have attempted to implement various solutions without much success. Struggling to upload a file and read its size through Node has left me frustrated. Initially, I tried using the f ...

Skipping certain key-value pairs during the conversion from JSON to Excel Worksheet using the XLSX library in JavaScript

I have a set of objects in JSON format within my JavaScript code and I am looking to transform this data into an Excel worksheet. Within the JSON structure, there are certain key-value pairs that I do not wish to include in the Excel output. For instance, ...

Vue websocket server could not be located

I've been struggling with this issue for a few days now and I can't seem to find a solution. Currently, I'm utilizing the vue-websocket library which can be found at (https://www.npmjs.com/package/vue-websocket) I've carefully followe ...

Weapons of Mass Destruction - receive markdown content

My application is utilizing a markdown editor from Google Code. $(document).ready(function () { var converter = Markdown.getSanitizingConverter(); var editor = new Markdown.Editor(converter); editor.run(); }); <div class="wmd-panel"> ...

Limit the vertical movement in Vue drag and drop operations

Currently, I am working on a project that involves implementing drag-and-drop functionality using vue-draggable. You can find more information about it here: https://github.com/SortableJS/Vue.Draggable. I am facing an issue where the height of the element ...

Creating a Vue application without the use of vue-cli and instead running it on an express

Vue has an interesting feature where vue-cli is not necessary for running it without a server. Initially, I thought otherwise. The Vue installation page at https://v2.vuejs.org/v2/guide/installation.html mentions using a script under CDN. <script src=&q ...

Best practices for building an Ember frontend and Node backend application

I'm currently working on a project that involves an ember frontend and a node backend. Within my ember-cli app, I've configured the .ember-cli file to proxy requests to node like this: { "proxy": "http://localhost:3000" } I've had to es ...

Giant Slide - navigate directly to a particular slide using a link

Hey there, I am currently working on incorporating the Superslide slider for fullscreen images in my website. My goal is to have a mostly text-free site where users can navigate through the images using the main menu or jump to a specific image within the ...