简体   繁体   English

如何将离子数据存储与 BehaviorSubject 和 Observable 一起使用

[英]How to use Ionic Data Storage with BehaviorSubject and Observable

I'm trying to create app with Angular 9 / Ionic 5我正在尝试使用 Angular 9 / Ionic 5 创建应用程序

I'm using Ionic Data Storage我正在使用离子数据存储

So, my auth.service.ts looks like:所以,我的auth.service.ts看起来像:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';

import { Storage } from '@ionic/storage'

import { BehaviorSubject, Observable, from } from 'rxjs'

@Injectable({
    providedIn: 'root'
})

export class AuthService {

    private currentTokenSubject: BehaviorSubject<string>
    public currentToken: Observable<string>

    constructor(
        private http: HttpClient,
        private storage: Storage,
    ) {
        this.getToken()
            .then(res => {
                this.currentTokenSubject = new BehaviorSubject(res)
                this.currentToken = this.currentTokenSubject.asObservable()
            }
        )
    }

    async getToken() {
        return await this.storage.get('accessToken')
    }

    public get currentTokenValue(): string {
        return this.currentTokenSubject.value;
    }

    login(username: string, password: string) {
        const headers = new HttpHeaders({
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'Authorization': 'Basic ' + btoa(username + ':' + unescape(encodeURIComponent(password)))
        })

        return this.http.post<Token>(`${environment.apiUrl}/auth/signin`, { }, { headers })
            .pipe(map((res: Token) => {
                let token = res.token
                // store user details and jwt token in local storage to keep user logged in between page refreshes
                this.storage.set('accessToken', token);
                return token;
            }));
    }

    logout() {
        // remove user from local storage to log user out
        this.storage.remove('accessToken');
        this.currentTokenSubject.next(null);
    }
}

and jwt.interceptor.ts looks like:jwt.interceptor.ts看起来像:

import { Injectable } from '@angular/core'
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'
import { Observable } from 'rxjs'

import { AuthService } from '@app/_services'

@Injectable()
export class JwtInterceptor implements HttpInterceptor {
    constructor(
        private authService: AuthService
    ) { }

    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // add authorization header with jwt token if available
        const currentToken = this.authService.currentTokenValue;

        if (currentToken) {
            request = request.clone({
                setHeaders: {
                    Authorization: `Bearer ${currentToken}`
                }
            });
        }

        return next.handle(request);
    }
}

So, when I try to call service, I get error, because Ionic Storage returns Observable:所以,当我尝试调用服务时,我得到了错误,因为 Ionic Storage 返回 Observable:

Error: Uncaught (in promise): TypeError: Cannot read property 'value' of undefined
TypeError: Cannot read property 'value' of undefined
at AuthService.get currentTokenValue [as currentTokenValue] (auth.service.ts:39)

Question is: What is the proper way to get value from Ionic Storage and use it?问题是:从 Ionic Storage 获取价值并使用它的正确方法是什么?

The issue you are trying to access the BehaviorSubject 's value getter before it is assigned any values.您在为其分配任何值之前尝试访问BehaviorSubjectvalue获取器的问题。 It is best to avoid the value getter and subscribe to the observable to keep things asynchronous.最好避免使用value getter 并订阅 observable 以保持异步。 Try the following尝试以下

auth.service.ts auth.service.ts

export class AuthService {
  private currentTokenSubject = new BehaviorSubject<string>(null); // <-- assign default value here

  constructor(
    private http: HttpClient,
    private storage: Storage,
  ) {
    this.getToken().then(
      res => {
        this.currentTokenSubject.next(res);               // <-- push token to the observable
      }
    );
  }

  async getToken() {
    return await this.storage.get('accessToken');
  }

  public get currentTokenValue(): Observable < string > {
    return this.currentTokenSubject.asObservable();        // <-- return observable here
  }

  login(username: string, password: string) {
    const headers = new HttpHeaders({
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Authorization': 'Basic ' + btoa(username + ':' + unescape(encodeURIComponent(password)))
    })

    return this.http.post<Token>(`${environment.apiUrl}/auth/signin`, {}, { headers }).pipe(
      map((res: Token) => {
        let token = res.token;
        // store user details and jwt token in local storage to keep user logged in between page refreshes
        this.storage.set('accessToken', token);
        this.currentTokenSubject.next(token);              // <-- also push new token here?
        return token;
      }));
  }

  logout() {
    // remove user from local storage to log user out
    this.storage.remove('accessToken');
    this.currentTokenSubject.next(null);
  }
}

Now you need to subscribe to the function currentTokenValue() to retreive the token.现在您需要订阅 function currentTokenValue()来检索令牌。

Some component/service一些组件/服务

export class SomeComponent implements OnInit {
  token: string;

  ngOnInit() {
    this.authService.currentTokenValue().subscribe(
      token => { 
        if(token) {       // <-- check if token valid because it can also be null
          this.token = token;
        }
      }
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM