rxjs在localstorage上的可观察角度2变化

Pra*_*hat 15 local-storage rxjs angular

我正在尝试创建一个observable,当localStorage变量发生更改时返回值.我的订户在更改localStorage时(或者在内存变量中)没有获得新值.

navbar.component.js

import { Component, OnInit } from '@angular/core';
import { UserService } from '../services/user.service';

/**
 * This class represents the navigation bar component.
 */
@Component({
  moduleId: module.id,
  selector: 'sd-navbar',
  templateUrl: 'navbar.component.html',
  styleUrls: ['navbar.component.css'],
  providers: [UserService]
})

export class NavbarComponent implements OnInit {
  loggedIn: boolean;
  constructor(private us: UserService) { }

  ngOnInit() {
    this.us.isLoggedIn().subscribe(loggedIn => {
      this.loggedIn = loggedIn;
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

auth.component.ts

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { UserService } from '../shared/services/user.service';

/**
 * This class represents the lazy loaded AuthComponent.
 */
@Component({
  moduleId: module.id,
  selector: 'sd-auth',
  templateUrl: 'auth.component.html',
  styleUrls: ['auth.component.css'],
  providers: [UserService]
})
export class AuthComponent implements OnInit {
  authParams = {
    provider: '',
    params: {}
  };

  constructor(private route: ActivatedRoute, private us: UserService) { }
  ngOnInit() {
    this.route.params.forEach((param) => {
      this.authParams.provider = param.authprovider;
    });

    this.route.queryParams.forEach((queryParams) => {
      this.authParams.params = queryParams;
    });

    this.us.logIn("google", JSON.stringify(this.authParams));

    console.log(JSON.parse(localStorage.getItem('authParams')));

  }
}
Run Code Online (Sandbox Code Playgroud)

user.service.ts

// user.service.ts
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subscriber } from 'rxjs/Subscriber';

@Injectable()
export class UserService {
  private loggedIn = false;
  private logger = new Observable<boolean>((observer: Subscriber<boolean>) => {
    observer.next(this.loggedIn);
  });
  constructor() {
    if (localStorage.getItem('authParams')) {
      this.loggedIn = !!JSON.parse(localStorage.getItem('authParams')).params.id_token;
    } else {
      this.loggedIn = false;
    }
  }

  logIn(provider: string, providerResponse: string) {
    localStorage.setItem('authParams', providerResponse);
    this.loggedIn = true;
  }

  isLoggedIn(): Observable<boolean> {
    return this.logger;
  }

  logOut() {
    localStorage.removeItem('authParams');
    this.loggedIn = false;
  }
}
Run Code Online (Sandbox Code Playgroud)

流程看起来像

步骤1- Navbar订阅UserService(获取默认值loggedIn = false)步骤2 - AuthComponent更新UserService(设置loggedIn = true)

我在Navbar中的订阅没有得到更新.我在这里想念的是什么 我是否需要在UserService的logIn方法中添加一些东西,比如事件发射器?

Fid*_*les 15

你想要的是一个主题.查看这里的文档(https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/subjects/subject.md)

举个简单的例子,像这样:

export class UserService {
  ...
  private logger = new Subject<boolean>();
  ...

  isLoggedIn(): Observable<boolean> {
    return this.logger.asObservable();
  }

  logIn(provider: string, providerResponse: string) {
    localStorage.setItem('authParams', providerResponse);
    this.loggedIn = true;
    this.logger.next(this.loggedIn);
  }

  logOut() {
    localStorage.removeItem('authParams');
    this.loggedIn = false;
    this.logger.next(this.loggedIn);
  }
...
Run Code Online (Sandbox Code Playgroud)


Ale*_*ing 7

我写了一个 StorageService 来支持 Observable localStorage 和 sessionStorage。它支持一项服务。

存储服务

import { BehaviorSubject, Observable } from 'rxjs';

/**
 * Storage service
 * used for persist application data in observable key value pair
 */
export class StorageService {

    private storage: Storage;
    private subjects: Map<string, BehaviorSubject<any>>;

    /**
     * Constructor with service injection
     * @param storage 
     */
    constructor(storage: Storage) {
        this.storage = storage;
        this.subjects = new Map<string, BehaviorSubject<any>>();
    }

    /**
    * watch data of given key
    * @param key 
    * @param defaultValue 
    */
    watch(key: string): Observable<any> {
        if (!this.subjects.has(key)) {
            this.subjects.set(key, new BehaviorSubject<any>(null));
        }
        var item = this.storage.getItem(key);
        if (item === "undefined") {
            item = undefined;
        } else {
            item = JSON.parse(item);
        }
        this.subjects.get(key).next(item);
        return this.subjects.get(key).asObservable();
    }

    /**
     * get data of given key
     * @param key 
     */
    get(key: string): any {
        var item = this.storage.getItem(key);
        if (item === "undefined") {
            item = undefined;
        } else {
            item = JSON.parse(item);
        }
        return item;
    }

    /**
     * set value on given key
     * @param key 
     * @param value 
     */
    set(key: string, value: any) {
        this.storage.setItem(key, JSON.stringify(value));
        if (!this.subjects.has(key)) {
            this.subjects.set(key, new BehaviorSubject<any>(value));
        } else {
            this.subjects.get(key).next(value);
        }
    }

    /**
    * remove given key
    * @param key 
    */
    remove(key: string) {
        if (this.subjects.has(key)) {
            this.subjects.get(key).complete();
            this.subjects.delete(key);
        }
        this.storage.removeItem(key);
    }

    /**
     * clear all available keys
     */
    clear() {
        this.subjects.clear();
        this.storage.clear();
    }
}
Run Code Online (Sandbox Code Playgroud)

本地存储服务

import { Injectable, Inject } from '@angular/core';
import { StorageService } from './storage.service';

/**
 * Local storage service
 * used for persist application data in observable key value pair
 */
@Injectable()
export class LocalStorageService extends StorageService {

    /**
     * Constructor with service injection
     * @param window 
     */
    constructor(@Inject('WINDOW') private window: any) {
        super(window.localStorage);
    }
}
Run Code Online (Sandbox Code Playgroud)

会话存储服务

import { Injectable, Inject } from '@angular/core';
import { StorageService } from './storage.service';

/**
 * Session storage service
 * used for persist application data in observable key value pair
 */
@Injectable()
export class SessionStorageService extends StorageService {

    /**
     * Constructor with service injection
     * @param window 
     */
    constructor(@Inject('WINDOW') private window: any) {
        super(window.sessionStorage);
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以通过以下方式使用该服务:

import { LocalStorageService } from './local-storage.service';

export class TestClass implements OnInit, OnDestroy {

    constructor(
        private localStorage: LocalStorageService,
    ) { }

    ngOnInit() {
        // get current value
        this.localStorage.get('foo');

        // set new value
        this.localStorage.set('foo', 'bar');

        // watch value changes
        this.localStorage.watch('foo').pipe(takeUntil(this.unsubscribe)).subscribe(foo => console.log('foo changed', foo));
    }

    ngOnDestroy() {
        this.unsubscribe.next();
        this.unsubscribe.complete();
    }
}
Run Code Online (Sandbox Code Playgroud)

(我真的是 TypeScript 的新手,有几个月的经验。欢迎提出任何改进建议:-))

  • 我对您的代码做了一些修改,并将BehaviorSubject 替换为ReplaySubject。:) https://stackblitz.com/edit/angular-ivy-9outi7?file=src%2Fapp%2Fservice.ts (2认同)

Mik*_*ler 5

另一种方法是观察storage事件

fromEvent(window, 'storage').subscribe((storageEvent) => {
  //do what you need to do with your storageEvent
})
Run Code Online (Sandbox Code Playgroud)

这意味着您不需要将本机 API 包装在任何服务层中。