Prevent data loss on webpage refresh by using Angular's local storage feature

As a beginner in Angular, I am exploring ways to retain user input and interactions on my webpage even after a refresh. After some research, I came across using local storage as a viable solution. A different answer suggested utilizing the following code snippets for setting and getting information:

Storage.prototype.setObj = function(key, obj) {
    return this.setItem(key, JSON.stringify(obj))
}
Storage.prototype.getObj = function(key) {
    return JSON.parse(this.getItem(key))
}

But, I still have a couple of lingering questions:

  1. I want the data to be saved upon refresh without continuous updates, so is there a way to handle this just before a refresh event? Or would it be necessary to constantly update local storage with every change?

  2. When should I retrieve the data? Would placing the get function in my constructor make sense for this purpose?

Answer №1

Responding to your inquiries

  1. To streamline auto-saving, simply save to localStorage whenever there is a change, but do so with a throttle (e.g. max once every second). There is an event that triggers when the tab is closed, onbeforeunload, although it may not fire if the tab crashes, and JavaScript's capabilities within this callback are limited.
  2. When the page is reloaded, it is advisable to use the data from localStorage to establish the initial state, so load the data in one of the constructors

By the way, utilize localStorage.getItem() and localStorage.setItem(). You do not need to set prototypes.

Answer №2

  1. It is not recommended to define any methods over a browser API prototype.
  2. Due to the asynchronous nature of localStorage, it is important to inform Angular about these changes in order for the ChangeDetector to function properly.

To address these issues in my projects, I have created a service:

import {Observable} from 'rxjs';
import {Injectable, NgZone} from '@angular/core';

@Injectable()
export class StorageService {
  private localStorage: Storage = localStorage;

  constructor(
    private _zone: NgZone
  ) {
  }

  /**
   * Set a key in the browser's localStorage
   * @param key
   * @param data
   * @returns {Observable<any>}
   */
  public set(key, data): Observable<any> {
    return new Observable((observer) => {
      this.localStorage.setItem(key, JSON.stringify(data));
      this._zone.run(() => {
        observer.next(true);
        observer.complete();
      });
    });
  }

  /**
   * Retrieve a key from the browser's localStorage
   * @param key
   * @returns {Observable<any>}
   */
  public get(key): Observable<any> {
    return this._zone.run(() => {
      return new Observable((observer) => {
        setTimeout(() => {
          observer.next(
            JSON.parse(this.localStorage.getItem(key))
          );
          observer.complete();
        }, 0);
      });
    });
  }

  /**
   * Remove a key from the browser's localStorage
   * @param key
   * @returns {Observable<any>}
   */
  public remove(key): Observable<any> {
    return new Observable((observer) => {
      this.localStorage.removeItem(key);
      this._zone.run(() => {
        observer.next();
        observer.complete();
      });
    });
  }
}

Simply add this service to your module providers, inject it into your controller or service, and start using it.

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

Tips for Sharing Multiple Nested Arrays in AngularJS

I am working with an array in AngularJS, and here is an example: $scope.order.qty='20'; $scope.order.adress='Bekasi'; $scope.order.city='Bekasi'; To post this array, I use the following code: $http({ method : &ap ...

Find out whether the object is located behind another item

Is there a method to determine if elementA is "obscured" by another element, meaning it is not visible to the user? We could potentially achieve this using stacking context, but the challenge lies in identifying which elements to compare. This would requi ...

"Seeking clarification on submitting forms using JQuery - a straightforward query

My goal is to trigger a form submission when the page reloads. Here's what I have so far: $('form').submit(function() { $(window).unbind("beforeunload"); }); $(window).bind("beforeunload", function() { $('#disconnectform&apo ...

The function 'create' is not a recognized property within the 'Completions' type

Recently, I've been experimenting with ChatGPT and have just installed the latest version 4.8.0. My current project is built on NextJS. Prior to this, I successfully completed a project using v3.something last month, but I'm encountering diffic ...

Mac users may experience lag when using Javascript parallax effects

I created a parallax page where the background image changes using JavaScript translateY(- ... px)' similar to what you see on the firewatch website. On Windows, the parallax effect works smoothly. However, on macOS it is smooth only in Safari. All ...

Iterating over an array of lists to tally the elements

I've been struggling to count the number of objects in an array using JavaScript. Below is the array I'm trying to work with: <script> var arr = [ {"gateways":["ccu1"],"manufacturer":["homematic"],"ir":["ir_no"],"ip":["ip_cam", ...

Creating a custom component results in an extended duration to 'eliminate' its children

1I am currently facing an issue with a time-table component created using vue.js. It contains approximately 200 nested child timeline components, making it quite complex (I wanted to share an image but lacked the reputation to do so). The main problem lie ...

What is the best way to remove all attributes from one interface when comparing to another?

Consider the following two interfaces: interface A { a: number; b: string; } interface B { b: string; } I am interested in creating a new type that includes all the keys from interface A, but excludes any keys that are also present in interface B. ...

Can you upload a file using the MaterialUI Upload Button in React and then send it to Firestorage?

Hi everyone! I recently implemented MaterialUI's Upload Button in my project, which you can find here: https://material-ui.com/components/buttons/ Below you will see the code snippet where I have integrated this button and now I am trying to upload a ...

Inquiring about the status of uploads in the AjaxFileUpload to ensure files have been successfully uploaded

How can I check if the file selected in AjaxFileUpload has already been uploaded or is pending? For example: https://i.stack.imgur.com/q6qUQ.png I want to validate files that are still pending upload. Here is my .aspx page code <form id="form1" runa ...

NodeJS: The module failed to automatically register itself

Exploring the capabilities of IBM Watson's Speech to Text API, I encountered an issue while running my NodeJS application. To handle the input audio data and utilize IBM Watson's SpeechToText package, I integrated the line-in package for streami ...

Display or conceal <ul>'s using JavaScript when the mouse enters or leaves

I'm encountering an issue with a basic JavaScript function. The goal is to toggle the dropdown menu on my website when the mouse hovers over or leaves the menu. The problem arises because my script is triggered by the ul tags within my menu, and I ha ...

Is there a way to stop the dropdown from automatically appearing in a DropDownList?

Seeking a solution to use a custom table as the dropdown portion for a DropDownList in my project. My goal is for users to see the custom table when they click on the DropDownList, rather than the default dropdown menu. I expected to be able to achieve th ...

Converting a database query result into a JavaScript variable: A step-by-step guide

I've been struggling with this problem for a day now and I feel like giving up. My main goal is to export the query result as a string (specifically dataString) so that I can easily import it as a string in my external .js file. module.exports.getKl ...

delivering the optimized main RequireJS file as a static asset through NGINX servers

Is it true that serving static assets from NGINX or another server is better than using your Node.js application server? In my case, I have a single-page application where in production mode, only one optimized .js file is served from the index page, and ...

When there is content behind the list, the Autosuggest Ajax does not function properly

I have successfully implemented an ajax/jquery dropdown/list feature that retrieves results from the database based on user input. For each result in the database, it generates a <li> element and converts it into a clickable link to redirect users t ...

Error in Node: JSON parse failure due to invalid token "'<'" and ""<!DOCTYPE ""

Every time I attempt to run node commands or create a new Angular project, I encounter the following error. Node version 20.11.0 NPM version 10.2.4 https://i.sstatic.net/Dg6BU.png https://i.sstatic.net/ZwN1Q.png ...

Encountering the error "Error: Maximum update depth exceeded" while coding a React private Route with infinite

Attempting to render components inside private routes only if the user is authenticated, but encountering an error message that reads: "Error: Maximum update depth exceeded." This issue typically arises when a component continuously calls setState within c ...

Making sure to detect page refresh or closure using jQuery or JavaScript

Could there be a way to determine if a page has been refreshed or closed using jQuery or javascript? The current scenario involves having certain database values that need to be deleted if the user either refreshes or leaves the page. AJAX calls are bein ...

Prevent unauthorized AJAX requests from external sources within the Node application

I am looking for a way to prevent AJAX requests from being made outside of my application. I need to ensure that the response is not sent when the AJAX request is initiated from external sources, even if the URL is copied and pasted into a browser. My te ...