为什么我的服务在我的应用组件上没有更新?[已关闭]

问题描述 投票:0回答:1

我正在使用Ionic 4,我想显示当前登录用户的信息,但是没有工作,我的意思是它在任何组件上都可以工作,除了应用程序组件,我使用了一个名为userData的变量,这是一个BehaviorSubject。你知道我的代码有什么问题吗?

auth.service.ts

import { Platform } from '@ionic/angular';
import { Injectable } from '@angular/core';
import { Storage } from '@ionic/storage';
import { BehaviorSubject, Observable, from, of, throwError } from 'rxjs';
import { take, map,tap, switchMap, catchError } from 'rxjs/operators';
import { JwtHelperService } from "@auth0/angular-jwt";
import { HttpClient } from '@angular/common/http';
import { Router } from '@angular/router';
import { Tokens } from '../models/tokens';
import { environment } from 'src/environments/environment';

const helper = new JwtHelperService();
//Agregar token access y refresh
const accessToken = 'access';
const refreshToken = 'refresh';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  public user: Observable<any>;
  private userData = new BehaviorSubject(null);
  private access: string = null;
  private refresh: string = null;
  constructor(private storage: Storage, private http: HttpClient, private plt: Platform, private router: Router) { 
    this.loadStoredTokens();  
  }

  getTokenExpirationDate(userData): Date {
    if (userData['exp'] === undefined) return null;

    const date = new Date(0); 
    date.setUTCSeconds(userData['exp']);
    return date;
  }

  isAcessTokenExpired(): boolean {
    let userData = this.userData.getValue();
    console.log(userData);
    if(!userData) return true;

    const date = this.getTokenExpirationDate(userData);
    if(date === undefined) return false;
    return !(date.valueOf() > new Date().valueOf());
  }

  loadStoredTokens() {
    let platformObs = from(this.plt.ready());

    this.user = platformObs.pipe(
      switchMap(() => {
        return from(this.storage.get(refreshToken));
      }),
      map(refreshToken => {
        if (refreshToken) {
          this.refresh = refreshToken;
        } else {
          this.refresh = null;
        }
      }),
      switchMap(() => {
        return from(this.storage.get(accessToken));
      }),
      map(accessToken => {
        if (accessToken) {
          this.access = accessToken;
          let decoded = helper.decodeToken(accessToken); 
          this.userData.next(decoded);
          return true;
        } else {
          this.access = null;
          return null;
        }
      })
    );

  }

  login(credentials: {username: string, password: string }) {
    return this.http
    .post(`${environment.apiUrl}/token/obtain/`,credentials)
    .pipe(
      take(1),
      map(res => {
        // Extract the JWT
        return res;
      }),
      switchMap(token => {
        let decoded = helper.decodeToken(token['access']);
        this.userData.next(decoded);

        from(this.storage.set(refreshToken, token['refresh']))
        let storageObs = from(this.storage.set(accessToken, token['access']));
        return storageObs;
      })
    );

  }

  getUser() {
    return this.userData.getValue();
  }

  logout() {
    this.storage.remove(accessToken).then(() => {

      this.storage.remove(refreshToken).then(() => {
        this.router.navigateByUrl('/');
        this.userData.next(null);
      });

    });
  }

getAccessToken() {
  return  this.access;
}

 getRefreshToken() {
  return this.refresh;
}

setAccessToken(token) {
  this.storage.set(accessToken, token);
}

  refreshToken() {
    return this.http.post<any>(`${environment.apiUrl}/token/refresh/`, {
    'refresh': this.getRefreshToken()
    }).pipe(tap((tokens: Tokens) => {
      this.setAccessToken(tokens.access);
      this.access = tokens.access;
    }));
  }
}

app.component.ts (我使用getUser()函数来获取当前用户信息)

import { Component, OnInit, ViewChildren, QueryList, OnChanges } from '@angular/core';

import { Platform, ModalController, ActionSheetController, PopoverController, IonRouterOutlet, MenuController } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';
import { Router } from '@angular/router';
import { faHome, faInfo, faFileContract } from '@fortawesome/free-solid-svg-icons';
import { ToastController } from '@ionic/angular';
import { AuthService } from './auth/services/auth.service';

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss']
})
export class AppComponent implements OnInit {
  public selectedIndex = 0;
  user = null;

  public appPages = [
    {
      title: 'Home',
      url: '/home',
      icon: faHome
    },
    {
      title: 'About',
      url: '/about',
      icon: faInfo
    },
    {
      title: 'Legal',
      url: '/legal',
      icon: faFileContract
    }
  ];


  constructor(
    private platform: Platform,
    private splashScreen: SplashScreen,
    private statusBar: StatusBar,
    public modalCtrl: ModalController,
    private menu: MenuController,
    private actionSheetCtrl: ActionSheetController,
    private popoverCtrl: PopoverController,
    private router: Router,
    public toastController: ToastController,
    private auth: AuthService
  ) {
    this.initializeApp();
  }



  initializeApp() {
    this.platform.ready().then(() => {
      this.statusBar.backgroundColorByHexString('#D4AF37');
      this.splashScreen.hide();
    });
  }

  ngOnInit() {

    this.user = this.auth.getUser();
    const path = window.location.pathname.split('home/')[1];
    if (path !== undefined) {
      this.selectedIndex = this.appPages.findIndex(page => page.title.toLowerCase() === path.toLowerCase());
    }



  }


}

app.component.html (这里我想显示用户信息,除了这个组件,其他组件的代码都是一样的)

<ion-app>
  <ion-split-pane contentId="main-content">
    <ion-menu contentId="main-content" type="overlay">
      <ion-content>
        <ion-list id="inbox-list">
          <ion-list-header>Menu</ion-list-header>
          <ion-note *ngIf="user">{{ user.email }} </ion-note>

          <ion-menu-toggle auto-hide="false" *ngFor="let p of appPages; let i = index">
            <ion-item (click)="selectedIndex = i" routerDirection="root" [routerLink]="[p.url]" lines="none" detail="false" [class.selected]="selectedIndex == i">
              <fa-icon (keyup)="onKeyFaIcon($event)" slot="start" [icon]="p.icon"></fa-icon>

              <ion-label>{{ p.title }}</ion-label>
            </ion-item>
          </ion-menu-toggle>
        </ion-list>

      </ion-content>
    </ion-menu>
    <ion-router-outlet id="main-content"></ion-router-outlet>
  </ion-split-pane>
</ion-app>
angular typescript ionic-framework ionic4
1个回答
0
投票

它出现在 userData 变量在函数中被赋予一个新的值 loadStoredTokens()login(). 我没看到 login() 在任何地方调用的函数和 loadStoreTokens() 函数被错误地同步调用。它处理数据是异步的,数据流也应该是异步的。

服务

export class AuthService {
  constructor(private storage: Storage, private http: HttpClient, private plt: Platform, private router: Router) { 
    this.loadStoredTokens().subscribe(
      accessToken => {
        let decoded = helper.decodeToken(accessToken); 
        this.userData.next(decoded);
      },
    );  
  }

  loadStoredTokens() {
    const result = new Subject<any>();
    let platformObs = from(this.plt.ready());

    this.user = platformObs.pipe(
      switchMap(() => {
        return from(this.storage.get(refreshToken));
      }),
      map(refreshToken => {
        if (refreshToken) {
          this.refresh = refreshToken;
        } else {
          this.refresh = null;
        }
      }),
      switchMap(() => {
        return from(this.storage.get(accessToken));
      }),
      map(accessToken => {
        if (accessToken) {
          this.access = accessToken;
          result.next(accessToken);
        } else {
          this.access = null;
          result.next(null);
        }
      })
    );

  return result.asObservable();
}

此外,如果你使用的是 getValue() 的功能 BehaviorSubject 并没有使用任何多播观察器。相反,你可以跳过 getValue() 的服务中,并在组件中订阅它。

服务中的

getUser() {
  return this.userData.asObservable();
}

组成部分

ngOnInit() {
  this.auth.getUser().subscribe(
    user => { this.user = user }
  );
}

使用安全导航仪 ?. 的模板中,检查是否有 user 变量在试图访问它的属性之前已经被定义。因为最初的值是 null 的默认值指定的。BehaviorSubject.

<ion-note *ngIf="user">{{ user?.email }} </ion-note>

或者,你可以跳过组件控制器中的订阅,而使用 async 模板中的管道。

组成部分

ngOnInit() {
  this.user = this.auth.getUser();
}

模板

<ion-note *ngIf="user">{{ (user | async)?.email }} </ion-note>

0
投票

因为BehaviorSubject是异步的,你需要订阅它。

ngOnInit() {
  this.auth.getUser().subscribe(user => this.user = user);
}

同时要记住,它不是即时的,所有的依赖性都在 this.user 也应该是异步的。

例如在模板中,你可以检查

<ng-container *ngIf="user">
  {{ user }} now we can use it
</ng-container>

0
投票

请使用async管道来实现。由于app加载时用户没有数据。请按照下面的代码,可能会对你有所帮助。

app.component.html

<ion-app>
<ion-split-pane contentId="main-content">
<ion-menu contentId="main-content" type="overlay">
  <ion-content>
    <ion-list id="inbox-list">
      <ion-list-header>Menu</ion-list-header>
      <ion-note *ngIf="user">{{ auth?.userData?.email | async }} </ion-note>
    </ion-list>
  </ion-content>
</ion-menu>
<ion-router-outlet id="main-content"></ion-router-outlet>

在userData对象中保留邮件属性。并保持AuthService作用域为public,同时在用户数据对象中注入。app.component.ts constructor.

© www.soinside.com 2019 - 2024. All rights reserved.