I am currently developing a web-app using Angular 8.
Within my app, I have a header and login page. My goal is to update the header after a user logs in to display information about the current logged-in user. I attempted to achieve this using a BehaviorSubject but unfortunately, it seems to be ineffective.
The issue lies within my authentication service where the BehaviorSubject is implemented
@Injectable()
export class AuthService {
private readonly GRANT_TYPE = 'password';
logged: BehaviorSubject<UserDataModel> = new BehaviorSubject<UserDataModel>(null);
//private auth$: Observable<Auth>;
constructor(private httpClient: HttpClient, private router: Router) { }
login(credentials: CredentialsModel) {
this.httpClient.post('http://localhost:8080/api/oauth/token',
this.prepareParams(credentials),
{ headers: this.prepareHeaders() })
.subscribe(token => {
let userData = new UserDataModel();
userData.token = token['access_token'];
this.getUserInfo(userData);
});
//this.saveAuth();
}
autoLogin() {
const userData = JSON.parse(localStorage.getItem('user'));
if (!userData) {
return;
}
if (userData.token) {
this.logged.next(userData);
}
}
private prepareHeaders(): HttpHeaders {
let headers = new HttpHeaders();
headers = headers.append('Authorization', 'Basic ' + btoa('frontendClientId:frontendClientSecret'));
headers = headers.append('Content-Type', 'application/x-www-form-urlencoded');
return headers;
}
private prepareParams(credentials: CredentialsModel) {
let params = new HttpParams();
params = params.append('username', credentials.username);
params = params.append('password', credentials.password);
params = params.append('grant_type', this.GRANT_TYPE);
return params;
}
private getUserInfo(userData: UserDataModel) {
this.httpClient.get('http://localhost:8080/api/user/user/current',
{headers: new HttpHeaders().append('Authorization', 'Bearer ' + userData.token)})
.subscribe(data => {
userData.email = data['name'];
userData.role = data['authorities'][0]['authority'];
this.saveUser(userData);
this.logged.next(userData);
this.router.navigate(['../']);
})
}
private saveUser(userData: UserDataModel) {
localStorage.setItem('user', JSON.stringify(userData))
}
}
Here is the code for my header component where I subscribe to the BehaviorSubject from the auth service
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit, OnDestroy, DoCheck {
loggedIn: boolean = false;
username: string ='';
private subscriptions: Subscription[] = [];
constructor(private authService: AuthService) { }
ngOnInit() {
this.subscriptions.push(this.authService.logged.subscribe(this.onLogged));
}
ngDoCheck(): void {
this.authService.autoLogin();
}
onLogout() {
this.loggedIn = false;
}
onLogged(userData: UserDataModel) {
if(userData) {
this.loggedIn = true;
this.username = userData.email;
}
}
ngOnDestroy(): void {
this.subscriptions.forEach(sub => sub.unsubscribe());
}
}
Below is some HTML code that fails to update after a user logs in:
<div class="header-actions" *ngIf="!loggedIn">
<a routerLink="/login" class="nav-link nav-icon-text">
<clr-icon shape="user"></clr-icon>
<span class="nav-text">Log In</span>
</a>
<a href="" class="nav-link nav-icon-text">
<clr-icon shape="plus"></clr-icon>
<span class="nav-text">Sign Up</span>
</a>
</div>
<div class="header-actions" *ngIf="loggedIn">
<clr-dropdown>
<button class="nav-text" clrDropdownTrigger>
{{username}}
<clr-icon shape="caret down"></clr-icon>
</button>
<clr-dropdown-menu *clrIfOpen clrPosition="bottom-right">
<a routerLink="#" clrDropdownItem>Profile</a>
<a routerLink="#" clrDropdownItem (click)="onLogout()">Logout</a>
</clr-dropdown-menu>
</clr-dropdown>
</div>
Within the login component, the 'login' method in the auth.service is correctly invoked, navigating to the dashboard, however, the header remains unchanged.
Can you provide insights into what might be causing this issue?