How can I watch for changes to localStorage in Angular2?

Use a service and only access LocalStorage through this service from everywhere.
The service can then provide observables that emit events on changes and you can subscribe to these observables to get notified.


The key thing is to use window.addEventListener("storage", . While the library probably does it the "right" way for angular, here is a "light" version I put together, using .bind(this) instead of mucking about in angular's internals.

    import { Injectable, OnDestroy } from '@angular/core';
    import { Subject } from 'rxjs/Subject';
    import { share } from 'rxjs/operators';
    
    @Injectable()
    export class StorageService implements OnDestroy {
      private onSubject = new Subject<{ key: string, value: any }>();
      public changes = this.onSubject.asObservable().pipe(share());
    
      constructor() {
        this.start();
      }
    
      ngOnDestroy() {
        this.stop();
      }
    
      public getStorage() {
        let s = [];
        for (let i = 0; i < localStorage.length; i++) {
          s.push({
            key: localStorage.key(i),
            value: JSON.parse(localStorage.getItem(localStorage.key(i)))
          });
        }
        return s;
      }
    
      public store(key: string, data: any): void {
        localStorage.setItem(key, JSON.stringify(data));
        this.onSubject.next({ key: key, value: data})
      }
    
      public clear(key) {
        localStorage.removeItem(key);
        this.onSubject.next({ key: key, value: null });
      }
    
    
      private start(): void {
        window.addEventListener("storage", this.storageEventListener.bind(this));
      }
    
      private storageEventListener(event: StorageEvent) {
        if (event.storageArea == localStorage) {
          let v;
          try { v = JSON.parse(event.newValue); }
          catch (e) { v = event.newValue; }
          this.onSubject.next({ key: event.key, value: v });
        }
      }
    
      private stop(): void {
        window.removeEventListener("storage", this.storageEventListener.bind(this));
        this.onSubject.complete();
      }
    }

LocalStorageTwoTabs


Updated version of https://stackoverflow.com/a/47683091/3098882 with new rxjs 6.

import { Injectable, OnDestroy } from '@angular/core';
import { Subject } from "rxjs";
import { share } from 'rxjs/operators';

@Injectable()
export class StorageService implements OnDestroy {
    private onSubject = new Subject<{ key: string, value: any }>();
    public changes = this.onSubject.asObservable().pipe(share());

    constructor() {
        this.start();
    }

    ngOnDestroy() {
        this.stop();
    }

    public getStorage() {
        let s = [];
        for (let i = 0; i < localStorage.length; i++) {
            s.push({
                key: localStorage.key(i),
                value: JSON.parse(localStorage.getItem(localStorage.key(i)))
            });
        }
        return s;
    }

    public store(key: string, data: any): void {
        localStorage.setItem(key, JSON.stringify(data));
        // the local application doesn't seem to catch changes to localStorage...
        this.onSubject.next({key: key, value: data})
    }

    public clear(key) {
        localStorage.removeItem(key);
        // the local application doesn't seem to catch changes to localStorage...
        this.onSubject.next({key: key, value: null});
    }


    private start(): void {
        window.addEventListener("storage", this.storageEventListener.bind(this));
    }

    private storageEventListener(event: StorageEvent) {
        if (event.storageArea == localStorage) {
            let v;
            try {
                v = JSON.parse(event.newValue);
            } catch (e) {
                v = event.newValue;
            }
            this.onSubject.next({key: event.key, value: v});
        }
    }

    private stop(): void {
        window.removeEventListener("storage", this.storageEventListener.bind(this));
        this.onSubject.complete();
    }
}