DEV Community

Cover image for Browser Storage and BehaviorSubject: Achieving Consistent State in Angular Through Storage Decorators
Saulo Dias
Saulo Dias

Posted on • Edited on

2

Browser Storage and BehaviorSubject: Achieving Consistent State in Angular Through Storage Decorators

Managing data persistence in Angular applications can be a hassle, especially when you need to keep your application state synchronized with local or session storage. In this post I will provide a set of property decorators that bind your storage values to BehaviorSubjects, ensuring that your state remains consistent with the browser's storage.

After test in production, I might consider publishing a library with them, but feel free to use the code as you wish. https://github.com/saulodias/ngx-storage

Why Use These Decorators?

They simplify the process of storing and retrieving data from local and session storage. They handle the heavy lifting for you.

With them you can:

  • Automatically sync your state with browser storage.
  • Use BehaviorSubject for reactive state management.
  • Easily revert to a fallback state when necessary.

How It Works

LocalStorage

The LocalStorage decorator allows you to store data in local storage effortlessly.

import { LocalStorage } from 'ngx-storage';
import { BehaviorSubject } from 'rxjs';

class TestClass {
    @LocalStorage('key', 'defaultValue')
    public localStorageValue!: BehaviorSubject<string | null>;
}
Enter fullscreen mode Exit fullscreen mode

SessionStorage

The SessionStorage decorator lets you store data in session storage just as easily.

import { SessionStorage } from 'ngx-storage';
import { BehaviorSubject } from 'rxjs';

class TestClass {
    @SessionStorage('key', 'defaultValue')
    public sessionStorageValue!: BehaviorSubject<string | null>;
}
Enter fullscreen mode Exit fullscreen mode

Custom JSON Converter

For more complex types, you can provide a custom JSON converter.

import { JsonConverter, SessionStorage } from 'ngx-storage';
import { BehaviorSubject } from 'rxjs';

type CustomType = { date: Date };
type CustomTypeStored = { date: number };

const customConverter: JsonConverter<CustomType, CustomTypeStored> = {
    toJson: (object) => ({ date: object.date.getTime() }),
    fromJson: (object) => ({ date: new Date(object.date) }),
};

class TestClass {
    @SessionStorage('key', { date: new Date() }, customConverter)
    public sessionStorageValue!: BehaviorSubject<CustomType | null>;
}
Enter fullscreen mode Exit fullscreen mode

Using NgxStorage in an Angular Service

Here's an example of how to use these decorators in an Angular service:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { LocalStorage, SessionStorage } from 'ngx-storage';

@Injectable({
    providedIn: 'root',
})
export class StorageService {
    @LocalStorage('localKey', 'defaultLocalValue')
    public localStorageValue!: BehaviorSubject<string | null>;

    @SessionStorage('sessionKey', 'defaultSessionValue')
    public sessionStorageValue!: BehaviorSubject<string | null>;

    constructor() {
        // Subscribe to localStorageValue
        this.localStorageValue.subscribe(value => {
            console.log('LocalStorage value:', value);
        });

        // Set a new value to localStorageValue
        this.localStorageValue.next('newLocalValue');

        // Subscribe to sessionStorageValue
        this.sessionStorageValue.subscribe(value => {
            console.log('SessionStorage value:', value);
        });

        // Set a new value to sessionStorageValue
        this.sessionStorageValue.next('newSessionValue');
    }
}
Enter fullscreen mode Exit fullscreen mode

Using the Service in a Component

import { Component, OnInit } from '@angular/core';
import { StorageService } from './storage.service';

@Component({
    selector: 'app-storage-example',
    templateUrl: './storage-example.component.html',
    styleUrls: ['./storage-example.component.css']
})
export class StorageExampleComponent implements OnInit {

    constructor(private storageService: StorageService) {}

    ngOnInit() {
        // Access and use the storage service properties as needed
        console.log('LocalStorage Initial:', this.storageService.localStorageValue.value);
        console.log('SessionStorage Initial:', this.storageService.sessionStorageValue.value);

        // Update the values
        this.storageService.localStorageValue.next('updatedLocalValue');
        this.storageService.sessionStorageValue.next('updatedSessionValue');
    }
}
Enter fullscreen mode Exit fullscreen mode

Setting Fallback State

When null is passed to .next(), the fallback state is set instead.

this.localStorageValue.next(null); // Reverts to 'defaultLocalValue'
this.sessionStorageValue.next(null); // Reverts to 'defaultSessionValue'
Enter fullscreen mode Exit fullscreen mode

Note that this is beta and not published, but you can use the code as you wish, for commercial and personal purposes. It's provided as it is though, with no guarantee.

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more