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

Utilizing SASS, JavaScript, and HTML for seamless development with Browser Sync for live syncing and

I've been on a quest to find a solution that covers the following requirements: Convert SASS to CSS Post-process CSS Minify CSS Move it to a different location Bundle all Javascript into one file Create compatibility for older browsers Tre ...

Content within iframe is failing to load correctly on both Firefox and Internet Explorer browsers

On my website, I have 4 iframes embedded in 4 different tabs. I've noticed that the content is being cropped when viewed on Firefox, but it loads properly when using Chrome. Strangely, if I manually reload the iframe, the content displays correctly. T ...

When using requirejs and vue.js together, the error message "Vue is not defined" may be encountered

My code snippet looks like this: <script type="text/javascript" src="../../node_modules/requirejs/require.js"></script> <script type="text/javascript" src="../../node_modules/vue/dist/vue.js"></script> <script>console.log(Vue ...

Nested pages in the NextJS router do not properly highlight the active menu item

I am currently working with NextJS and facing an issue with setting active menu items using the router. While the 'top level' pages behave as expected, any page under a top level page does not get set as active. router.pathname == "/profile& ...

The implementation of a universal translation system in Express JS

I have developed a straightforward translation module for Express JS. It exists as a global object in the application scope and is initialized during application runtime: translator.configure({ translations: 'translations.json' }); I have i ...

Using PHP to send asynchronous requests to the server can greatly enhance

I have almost completed my project, but I am facing an issue with reading the data sent to the server. function main() { jQ(document).on("keyup", "form input", function () { var data = new FormData(); var value = jQ(this).val(); da ...

What is the best way to break out of a function halfway through?

What are your thoughts on using nested if statements? $scope.addToCart = function () { if (flagA) { if (flagB) { if (flagC) { alert('nononono!'); return; } } } e ...

Develop a dynamic product filtering system in VueJS 3 with interdependent parameters

I'm aiming to develop a product filtering system that operates with mutual dependence just like the ones seen on e-commerce platforms. For instance, if I choose option X in the first filter, then the second filter should only show products correspondi ...

Click on the button without any reaction

I'm having trouble with the button. When I click on the button with ng-click="goSearchTitle()", nothing happens. Any idea why it's not working? <body ng-app="myapp"> <div ng-contoller="searchbyTitle"> <h3>Sea ...

next-redux-wrapper is being invoked repeatedly and experiencing multiple calls to HYDRATE

I'm embarking on a new Next.js project, transitioning from a standard React app to a Next.js application. Our plan is to utilize Redux Toolkit for global state management and incorporate server-side rendering. During this process, we discovered the ne ...

Backbone sorting is specifically designed for organizing views within the framework

As I work on creating a sorting function in backbone, I have come across recommendations to use views to listen for changes in collections and then render the views once the collections are sorted. However, this approach does not suit my needs for two main ...

Issues with setting headers after they have been sent - Can you explain why?

How am I setting a header after it has been sent to the client? Here is the code snippet: When a form is submitted, a post ajax request is triggered which returns a JSON object to the client. I have commented out most of the code to troubleshoot, and cur ...

Ways to interact with similar dynamic controls in Javascript

I have an aspx page with a Select box control: <select name="selViewPerPage" id="selViewPerPage" style="width:30px"> To ensure consistent styling across all browsers, I am replacing this html control with a dynamic select box using "selectBox.js". ...

Having trouble with Django's submit POST method for creating objects

Latest Updates: I have successfully implemented a feature where the page does not reload upon clicking the submit button. To achieve this, I filled out the form and inspected the page source code. The form structure was as follows: The corresponding sou ...

Is there a way to retrieve the response body in Express framework?

In my NodeJS API using Express, I am attempting to save the response body of a request. To achieve this, I have created two middleware functions. app.use((req, res,next) => { res.status(404).json({ errors: [{ field: "url", ...

Utilizing Google App Engine for seamless deployment, integrating Ajax for dynamic interactions, and

Using the google App Engine, I am looking to implement javascript (or Ajax) for POSTing a form and updating the target div. The form includes multiple fields and files for transfer. The javascript function I am using is extracted from the "Javascript: The ...

Simplified method for creating Angular templates

Take a look at this code snippet my_app.run( [ '$templateCache' , function( $templateCache ) { var template = "" + "{{ item.name }}" + "<ul ng-if='item.sub'>" + "& ...

What is the method for adding an event listener in AngularJS within an ng-repeat iteration?

I'm completely new to AngularJS and currently working on building a photo gallery. The basic idea is to have an initial page displaying thumbnail photos from Twitter and Instagram using an AngularJS ng-repeat loop. When a user hovers over an image, I ...

Update the Ngrx reducer when the component is present on the page

One dilemma I am facing involves managing two components within a page - an update user form and a history of events. Each component has its own reducer (user and events). My goal is to update the list of events in the store through an API call once the us ...

What could be causing the <img src= ' '/> tag to malfunction in Express?

While learning about HTML, I noticed that simply using img src="...." worked fine. However, when working with Express, the same code did not work! The documentation mentioned that I needed to place the images in a folder named public, require(&ap ...