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

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.

Top comments (0)