【发布时间】:2021-02-14 12:26:08
【问题描述】:
在我的导航栏中有一个用于登录和用户选项的下拉菜单。使用 ngIf 我会根据需要显示和隐藏每个菜单。例如,当用户未登录时,我会显示:
但是,当某些用户登录时,我会显示这个:
我通过询问我的后端令牌是否有效并且用户已登录来做到这一点。我使用订阅来做到这一点。问题是当我单击“登录”或“退出”时,组件不会重新加载。我需要重新加载页面才能正常工作。在不重新加载所有页面的情况下从订阅中获取新价值的最佳方法是什么?因为我不认为重新加载所有页面对用户来说是一种很好的体验。
这是我的代码:
navbar.component.html
<ul class="navbar-nav mr-right py-0">
<li *ngIf="!isLogged; else elseBlock" class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Sign in or register
</a>
<div class="dropdown-menu p-3 dropdown-menu-right">
<app-login></app-login>
</div>
</li>
<ng-template #elseBlock>
<li class="nav-item dropdown">
<a class="nav-link py-0" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img src="{{avatarUrl}}" class="rounded-circle d-inline-block p-0 profile-img mx-3" alt="{{username}} avatar">
<span class="dropdown-toggle p-0 m-0 align-middle">{{username}}</span>
</a>
<ul class="dropdown-menu-right dropdown-menu" aria-labelledby="dropdownMenuLink">
<li><span class="dropdown-item clickable" (click)="goToProfile()">Profile</span></li>
<li><span class="dropdown-item clickable" (click)="logout()">Sign out</span></li>
</ul>
</li>
</ng-template>
</ul>
navbar.component.ts
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Subscription } from 'rxjs';
import { AccountService } from '../account/account.service';
import { AuthService } from '../auth/auth.service';
@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss']
})
export class NavbarComponent implements OnInit {
isLogged: boolean;
avatarUrl: string;
username: string;
isLogged_subscription: Subscription;
avatar_subscription: Subscription;
username_subscription: Subscription;
constructor(private authService: AuthService, private accountService: AccountService, private router: Router) { }
ngOnInit(): void {
this.isLogged_subscription = this.authService.isLogged().subscribe(
value => {
this.isLogged = value;
}
);
this.avatar_subscription = this.accountService.getAvatar().subscribe(
value => {
this.avatarUrl = value;
}
);
this.username_subscription = this.accountService.getUsername().subscribe(
value => {
this.username = value;
}
);
}
logout(): void {
this.authService.logout();
}
goToProfile(): void {
this.router.navigateByUrl('/profile')
}
}
auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { tap } from 'rxjs/operators';
import { Observable, BehaviorSubject } from 'rxjs';
import { UserI } from '../models/user';
import { ServerResponseI } from '../models/server-response';
import { environment } from '../../environments/environment';
@Injectable({
providedIn: 'root'
})
export class AuthService {
constructor(private httpClient: HttpClient) { }
register(user: UserI): Observable<ServerResponseI> {
return this.httpClient.post<ServerResponseI>(`${environment.apiBase}/account/register`, user).pipe(
tap(
(res: ServerResponseI) => {
if(res){
this.saveToken(res.token, res.expiry)
}
}
)
);
}
login(user: UserI): Observable<ServerResponseI> {
return this.httpClient.post<ServerResponseI>(`${environment.apiBase}/account/get_token/`, user).pipe(
tap(
(res: ServerResponseI) => {
if(res){
this.saveToken(res.token, res.expiry)
}
}
)
);
}
isLogged(): Observable<boolean> {
return this.httpClient.get<boolean>(`${environment.apiBase}/account/is_logged/`);
}
logout(): void{
localStorage.removeItem("ACCESS_TOKEN");
localStorage.removeItem("EXPIERES_IN");
}
private saveToken(token: string, expiresIn: string): void {
localStorage.setItem("ACCESS_TOKEN", token);
localStorage.setItem("EXPIERES_IN", expiresIn);
}
}
【问题讨论】:
-
为什么不公开一个登录状态的observable,而不是一个订阅?
-
@jonrsharpe 实际上,这是我使用 Angular 的第一步。我可以通过保存 observable 而不是订阅来解决它吗?
标签: angular authentication service frontend