Rxjs наблюдаемый angular 2 при изменении localstorage

Я пытаюсь создать наблюдаемый, который возвращает значения при изменении переменной 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;
    });
  }
}

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')));

  }
}

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;
  }
}

Поток выглядит как

Шаг 1- Navbar подписывается на UserService (получает значение по умолчанию loggedIn = false) Шаг 2 - AuthComponent обновляет UserService (устанавливает loggedIn = true)

Моя подписка в Navbar не обновляется. Что мне здесь не хватает. Нужно ли мне что-то помещать в методе logIn UserService, таком как эмиттер событий?

Ответ 1

То, что вы хотите, это предмет. Проверьте документы здесь (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);
  }
...

Ответ 2

Чтобы быть более точным, используйте BehaviourSubject из import { BehaviorSubject } from 'rxjs/BehaviorSubject';

Для ex:

@Injectable()
export class UserService {

  public username = new BehaviorSubject<string>('');
  public preferredLanguage = new BehaviorSubject<string>('');
  public preferredTimezone = new BehaviorSubject<string>('');

  constructor(
    private router: Router,
    private jwtTokenService: JwtTokenService
  ) {
    let token: string = localStorage.getItem('token'); // handled for page hard refresh event
    if (token != null) {
      this.decode(token);
    }
  }

  private decode(token: string) {
    let jwt: any = this.jwtTokenService.decodeToken(token);
    this.username.next(jwt['sub']);
    this.preferredLanguage.next(jwt['preferredLanguage']);
    this.preferredTimezone.next(jwt['preferredTimezone']);
  }

  public setToken(token: any) {
    localStorage.setItem('auth_token', token);
    this.decode(token);
  }

}

и узнать разницу между BehaviorSubject и Observable: Angular 2 - Предмет поведения vs Наблюдаемый?

Ответ 3

Альтернатива - наблюдать событие storage

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

Это означает, что вам не нужно оборачивать нативный API на любом слое сервиса.