【问题标题】:Why Subject subscribe is not working in Angular 9为什么主题订阅在 Angular 9 中不起作用
【发布时间】:2020-09-17 20:50:15
【问题描述】:

我在身份验证服务中定义了一个主题。当我想将用户信息移动到另一个组件时,订阅不起作用,它也不起作用。我尝试在不同的钩子中使用它,但它又没用。我也使用了 BehaviorSubject,但返回 null。

有谁知道问题出在哪里?

auth.service.ts

import {Injectable} from '@angular/core';
import {HttpClient, HttpErrorResponse, HttpHeaders} from '@angular/common/http';
import {AuthModel} from '../Infrastructure/Models/authModel';
import {RegisterUserDeviceModel} from '../Infrastructure/Models/RegisterUserDeviceModel';
import {ResponseModel} from '../Infrastructure/Models/responseModel';
import {RegisterUserDeviceResponseModel} from '../Infrastructure/Models/registerUserDeviceResponseModel';
import {LoginResponseModel} from '../Infrastructure/Models/LoginResponseModel';
import {RegisterDeviceDataMosel} from '../app.component';
import {BehaviorSubject, Subject, throwError} from 'rxjs';
import {UserDataModel} from '../Infrastructure/Models/UserDataModel';
import {catchError, tap} from 'rxjs/operators';
import {RoleEnum} from '../Infrastructure/Enums/RoleEnum';

@Injectable({
    providedIn: 'root'
})
export class AuthService {
    devicecode: string = (<RegisterDeviceDataMosel> JSON.parse(localStorage.getItem('RegisterDeviceData'))).devicecode;
    user = new Subject<UserDataModel>();

constructor(private _http: HttpClient) {
}

Signin(data: AuthModel) {
    let _headers = new HttpHeaders();
    _headers = _headers.append('Content-Type', 'application/json');
    _headers = _headers.append('Access-Control-Allow-Origin', '*');
    _headers = _headers.append('X-Skip-Interceptor', '');
    _headers = _headers.append('device_code', this.devicecode);
    const _options = {headers: _headers};

    return this._http.post<ResponseModel<LoginResponseModel>>('http://localhost:5000/account/login', data, _options)
        .pipe( catchError(this.handelError) , tap(resData => {
            this.handleAuth(data.username, resData.response.access_token, resData.response.refresh_token
                , resData.response.role, resData.response.expires_in);
        }));
}

AutoLoading(): boolean {
    debugger;
    const userData: {
        username: string,
        access_token: string,
        refresh_token: string,
        role: RoleEnum,
        _tokenexpirationDate: string
    } = JSON.parse(localStorage.getItem('userData'));
    if (!userData) {
        return false;
    }
    const loadUser = new UserDataModel(userData.username, userData.access_token, userData.refresh_token
        , userData.role, new Date(userData._tokenexpirationDate));
    if (loadUser.token) {
        this.user.next(loadUser);
        return true;
    }
}

private handleAuth(username, token, refresh_token, role, expiresin) {
    const expirationDate = new Date(new Date().getTime() + +expiresin * 60000);
    const user = new UserDataModel(username, token, refresh_token
        , role, expirationDate);
    debugger;
    this.user.next(user);
    localStorage.setItem('userData', JSON.stringify(user));
}

private handelError(errorResponse: HttpErrorResponse){
    return throwError(errorResponse);
}
}

组件

import {AfterViewChecked, AfterViewInit, Component, OnDestroy, OnInit} from '@angular/core';
import * as momenthijri from 'moment-hijri';
import {AuthService} from '../../auth/auth.service';
import {Subscription} from 'rxjs';



@Component({
  selector: 'app-footer',
  styleUrls: ['./footer.component.scss'],
  templateUrl: './footer.component.html',
  providers: [AuthService]
})
export class FooterComponent implements OnInit , OnDestroy {
  private userSub: Subscription ;
  nowDate = new Date();
  hijri;
  public userName;
  public role;

  constructor(private authService: AuthService) {
  }

  ngOnInit(): void {
    this.hijri = momenthijri(this.nowDate.toString()).format('iYYYY/iM/iD');
    this.userSub = this.authService.user.subscribe( res =>{
      debugger;
      this.userName = res.username ;
      this.role = res.role;
    });
  }

  ngOnDestroy(): void {
    this.userSub.unsubscribe();
  }
}

谢谢大家的帮助

【问题讨论】:

  • 它是否进入了您的 handleAuth 方法?尝试将控制台日志放入该方法中?
  • 是的。该方法有效。
  • 在调用 next 之前尝试打印用户对象?

标签: angular typescript rxjs subject


【解决方案1】:

这是因为Subject 没有将数据存储在其中,您必须在在您的主题中提供数据之前订阅。另外,你可以使用BehaviorSubject里面存储数据,你订阅它的时候你会收到这个数据,但是你必须提供一个初始值。

另一方面,您可以通过user = new ReplaySubject&lt;UserDataModel&gt;(1)模拟没有初始值的BehaviorSubject,它将存储最后的数据并在您每次订阅时返回。希望,我的解释很清楚:)

【讨论】:

  • 感谢您的回复。我将 BehaviorSubject 的初始值设为空。已输入此方,但在订阅中输入了空值。有什么问题?
  • 您需要致电AutoLoadingSignin,然后您才会收到该用户。但是请注意,当您调用AutoLoading 时,由于此方法中的if 条件,您必须确保在本地存储中为loadUser.token。此外,当您致电 Signin 时,您必须等到您的 post 方法得到响应。
猜你喜欢
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 2020-12-13
  • 2018-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多