Unable to store the array in the local storage

Background: In an attempt to implement a "Favourites List" feature where users can add favorite categories with heart icons on the home page, I encountered challenges. Despite searching for a logical flow on Google, I couldn't find a helpful solution. To address this, I initially created a logic where clicking the heart button would check whether the section is already in the FavList array, which currently only accepts one section as a prototype. While the heart buttons worked correctly, I faced the issue of the FavList becoming empty after refreshing the page.

For example, in the vegetables section (food.component.html):

<div class="row">
            <div class="col-10">
                <h3 class="mb-3 d-inline">Vegetables
                    <button class="btn" (click)="addFavVeg()">
                        <i class="bi align-items-center border-0 text-danger" [ngClass]="favList.includes('vegetables') ? 'bi-heart-fill':'bi-heart'" id="vegetables"></i>
                    </button>
                </h3>
            </div>

In food.component.ts:

export class FoodComponent implements OnInit {

  foodList: Product[]
  favList: string[] = this.productsService.favList

  addFavVeg() {
    this.productsService.addFavVeg()
  }

  addFavFruits() {
    this.productsService.addFavFruits()
  }

  constructor(private productsService: ProductsService) {}

  ngOnInit() {
    this.productsService.saveData('favList', JSON.stringify(this.favList))
    this.productsService.getData('favList')
    console.log(this.productsService.getData('favList'))
    return this.productsService.findAllFood().subscribe(data => {
      this.foodList = data
    })
  }

}

I made the decision to relocate functions to the service where local storage functionalities are located.

In products.service.ts:

export class ProductsService {

  favList: string[] = []

  addFavVeg() {
    if (this.favList.includes('vegetables')) {
      this.favList.pop();
    }
    else if (this.favList.length > 0){
      this.favList.pop();
      this.favList.push('vegetables');
    }
    else {
      this.favList.push('vegetables');
    }
    this.saveData('favList', this.favList)
    console.log(this.getData('favList'))
  }

  addFavFruits() {
    if (this.favList.includes('fruits')) {
      this.favList.pop();
    }
    else if (this.favList.length > 0){
      this.favList.pop();
      this.favList.push('fruits');
    }
    else {
      this.favList.push('fruits');
    }
    this.saveData('favList', this.favList)
    console.log(this.getData('favList'))
  }

  public saveData(key, value) {
    localStorage.setItem(key, value)
  }

  public getData(key) {
    JSON.parse(localStorage.getItem(key))
    console.log(JSON.parse(localStorage.getItem(key)))
  }
}

Upon checking the browser, the heart buttons remained functional. However, a console error was thrown preventing local storage from saving the added values to the array: the error

Despite further exploration into local storage usage, integrating it with my favList concept remains a challenge. Any suggestions or solutions?

When attempting to save the FavList array in local storage, I expected confirmation in the console showing the array with either 'vegetables' or 'fruits' value. Instead, I encountered an error related to JSON serialization.

Answer №1

Consider revising your getData method to handle different data types more effectively:

public fetchData(key: string): string | null {
    const data = localStorage.getItem(key);
    console.log(data != null ? JSON.parse(data) : "not found");
    return data != null ? JSON.parse(data) : null;
}

I encountered an issue with your original code where the typescript compiler flagged an error due to localStorage.getItem(key) potentially returning a value of null. Since JSON.parse requires a string input, it cannot process null values properly.

Answer №2

Initially, I decided to replace the old [ngClass] expression with a function

In the food.component.html:

<div class="row">
            <div class="col-10">
                <h3 class="mb-3 d-inline">Vegetables
                    <button class="btn" (click)="addFavVeg()">
                        <i class="bi align-items-center border-0 text-danger" [ngClass]="isVegs() ? 'bi-heart-fill':'bi-heart'" id="vegetables"></i>
                    </button>
                </h3>
            </div>

I made this change as a preventive measure to avoid potential issues in retrieving data from the service to the component. Subsequently, I updated

favList = this.getData("favList")
so that it reflects changes every time a button is clicked.

Below is the code for better comprehension:

In food.component.ts:

  addFavVeg() {
    this.productsService.addFavVeg()
  }

  addFavFruits() {
    this.productsService.addFavFruits()
  }

  isVegs() {
    return this.productsService.isVegs()
  }

  isFruits() {
    return this.productsService.isFruits()
  }

  constructor(private productsService: ProductsService) {}

The entire logic has now been properly integrated into products.service.ts:

favList: string[] = this.getData("favList")

  addFavVeg() {
    if (this.favList.includes("vegetables")) {
      this.favList.pop();
    }
    else if (this.favList.length > 0){
      this.favList.pop();
      this.favList.push("vegetables");
    }
    else {
      this.favList.push("vegetables");
    }
    this.saveData("favList", this.favList)
  }

  addFavFruits() {
    if (this.favList.includes("fruits")) {
      this.favList.pop();
    }
    else if (this.favList.length > 0){
      this.favList.pop();
      this.favList.push("fruits");
    }
    else {
      this.favList.push("fruits");
    }
    this.saveData("favList", this.favList)
  }

  isVegs(): boolean {
    return this.favList.includes('vegetables')
  }

  isFruits(): boolean {
    return this.favList.includes('fruits')
  }

  public saveData(key: string, value: string[]) {
    localStorage.setItem(key, JSON.stringify(value))
  }

   // changed string to string[]
   public getData(key): string[] | null {
    const data = localStorage.getItem(key);
    // console.log(data != null ? JSON.parse(data): "not found");
    return data != null ? JSON.parse(data) : null;
  }

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

When accessing a method exposed in Angular2 from an external application, the binding changes are lost

In my code, I have a method that is made public and accessible through the window object. This method interacts with a Component and updates a variable in the template. However, even after changing the value of the variable, the *ngIf() directive does not ...

When utilizing await/async in TypeScript with Axios, the return type may be incorrect

UPDATE: After some investigation, it turns out the issue was not related to Axios or TypeScript but rather a strange IDE configuration problem. Starting fresh by recreating the environment and .idea folder solved the issue. While working with Axios in Typ ...

Obtaining JSON data created through the use of the stringify method

After retrieving data from a database, I stored it in an array. To convert this array into JSON format, I used the stringify method which resulted in the following JSON structure: var view_data = [{ f o o = " boo " , t e x t = "t e s t " }]; However, w ...

Transforming a transmitted statement

Is it possible to get the following broadcasted expression working? J = rand(4,4) fx1 = rand(2,2) fx2 = rand(2,2) @. J[:,1] = fx1 + fx2 I am really interested in achieving something like: @. J[:,1] = vec(fx1 + fx2) The idea is to reshape it without all ...

Building upon the foundation: Extending a base component in Angular

I have a Base Component that is extended by its children in Angular. However, when creating a new Component using angular-cli, it generates html and css files that I do not need for the base component. Is there a way to create a Base Component without inc ...

While iterating through the material-ui rating component, the 'index' value remains constant at 0 within the 'onChange' function

For my e-commerce React.js web app, I want to show the rating value of each product. Using the JS map function, I was able to track which product was hovered by its index ('onChangeActive' is the handler for this). {products.map((product, index) ...

Can you identify the TypeScript type for an array containing various Angular components?

In my application, I have a diverse range of components that I would like to organize into an array. There are no restrictions on what types of components can be included in this array, as long as they are Angular components. What is the correct way to de ...

Ways to remove an item from an array

I need some help with dropping a student from a course. Here is the code I have so far: public void removeStudent() { String id; System.out.println("Enter student ID: "); id = Keyboard.readString(); for (int i = 0; i <= students.length - 1; i++) ...

Access the elements within arrays without using the square brackets

I am trying to access data from a list, but I am having trouble using square brackets []. The getTalonPaie function calls the get method from the HttpClient service and returns an observable with multiple values. However, when I try to store these values i ...

Angular 2's Implementation of Hierarchical Dependency Injection

I'm encountering a problem with my Angular 2 application. I have a root component, AppComponent, where I've injected a service called ProductService. Now, I am trying to resolve this service in one of the child components, ProductList, but I keep ...

Guide on handling OnChanges in conjunction with AfterViewInit

Utilizing D3 with Angular2, I have been following a specific example provided here. The structure of my component is as follows: @Component({ selector: 'example-component', template: '<div #someElement></div>' }) class exam ...

Positioning dropup and dropdowns in ng-bootstrap on a single page

Is it possible to have both dropdown and dropup options on the same page using ng-bootstrap? I attempted to implement the code provided in the ng-bootstrap documentation, but it only allows for a global configuration of dropdowns. I specifically need ...

Utilize Angular 7 to incorporate properties into a reusable template

Throughout my project, I have been using a template extensively: <div class="col-xs-6 event" *ngFor="let event of events"> <h1>{{ event.title }}</h1> <p>{{ event.content }}</p> </div> This template utilizes various ...

How come the hook keeps triggering endlessly in a loop when I try to pass the updated props?

I've encountered an issue with a custom hook I created for making HTTP requests. The problem is that the request seems to be firing in an endless loop, and I'm unsure of what's causing this behavior. My intention is for the request to only t ...

Angular 4 async pipe not functioning as expected for Observable to update UI

I have a simple dataset loaded into an observable as shown below: public tasks: Observable<UserTask[]>; constructor(private dataService: HttpdataService, private changeDetector: ChangeDetectorRef) { } ngOnInit() { this.loadTasks(); } loadTasks() ...

What makes pagination malfunction in Bootstrap?

I attempted to implement pagination using the example provided at the following link: (located under Pagination) However, the pagination feature is not functioning correctly for me. Specifically, when I tried to display only 3 lines on the first page by ...

Issue encountered with subscripted value that is not classified as an array, pointer, or vector

void create_game_grid(struct game_board *board, FILE *output) { int rows, cols; /* Allocate memory for the correct number of rows */ board->grid = malloc(sizeof(*board->grid) * (board->numRows + 4)); for (rows = 0 ...

value on the horizontal axis of a highchart

Highcharts is my go-to tool for creating charts, and it's been working great. However, I'm now facing an issue with getting the values from my MySQL results. Here's what I've tried so far: xAxis: { dateTimeLabelFormats: { ...

Angular is failing to transfer control to the Web API

I'm currently utilizing a SQLite database and attempting to insert a record into the 'Departments' table. Below is the code snippet from my Web API controller: [HttpPost] public async Task<ActionResult> SaveDept(CreateDepartmentDto de ...

Access an external URL by logging in, then return back to the Angular application

I am facing a dilemma with an external URL that I need to access, created by another client. My task is to make a call to this external URL and then return to the home page seamlessly. Here's what I have tried: <button class="altro" titl ...