I have successfully implemented a login service for my Angular 2 app. What I want to do now is provide the username of the logged-in user from that component to a separate component - specifically the chat component.That way I can display the user's name when they are chatting with another user. I'm still a little hazy on how you pass values like this from one component to another in Angular 2. Here is the code from my login component:
import { AuthenticationService } from './../../data/authentication.service';
import { AlertService } from './../../data/alert.service';
import { Component, OnInit, Output } from '#angular/core';
import { Router } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: 'app/views/login/login.component.html',
styleUrls: ['app/views/login/login.component.css']
})
export class LoginComponent implements OnInit {
//#Output() username;
model: any = {};
loading = false;
constructor(
private router: Router,
private authenticationService: AuthenticationService,
private alertService: AlertService) { }
ngOnInit() {
// reset login status
this.authenticationService.logout();
}
login() {
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password)
.subscribe(
data => {
this.router.navigate(['/']);
console.log('User logged in as: ' + this.model.username);
},
error => {
this.alertService.error(error);
this.loading = false;
});
}
reqPasswordReset() {
let popup = document.getElementById('myPopup');
popup.classList.toggle('show');
}
}
This component make use of an authentication service, which looks like this:
import { LoginComponent } from './../views/login/login.component';
import { ContextMenu } from './../ui/context-menu.component';
import { Router, RouterLinkActive } from '#angular/router';
import { Injectable } from '#angular/core';
import { Http, Headers, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class AuthenticationService {
constructor(private http: Http) {}
login(username: string, password: string) {
return this.http.post('/api/authenticate', JSON.stringify({ username: username, password: password }))
.map((response: Response) => {
// login successful if there's a jwt token in the response
let user = response.json();
if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
}
});
}
isAuthenticated() {
if (localStorage.getItem('currentUser')) {
//console.log('User successfully authenticated...');
return true;
} else {
// console.log('User is not authenticated...');
return false;
}
}
logout() {
// remove user from local storage to log user out
localStorage.removeItem('currentUser');
console.log('User successfully logged out');
}
}
I'm able to successfully log to the console the username, so I know I'm capturing that value. What I'd like to do is now pass that value from "this.model.username" to my room component, which currently looks like this:
import { ChatService } from './../chat/chat.service';
import { User } from './../../views/user/user';
import { Component, OnInit, Input } from '#angular/core';
import { AuthenticationService } from './../../data/authentication.service';
import { Http, Headers, Response } from '#angular/http';
import { Router } from '#angular/router';
#Component({
selector: 'app-room',
templateUrl: './room.component.html',
styleUrls: ['./room.component.less']
})
export class RoomComponent implements OnInit {
otherImg = 'app/img/photo-ph.png';
// otherImg = 'app/img/portrait-place-holder.svg';
model: any;
loading = false;
others = [
{ id: 1, name: 'John Smith', avatar: 'app/img/photo-ph.png' },
{ id: 2, name: 'Javier Sanchez', avatar: 'app/img/photo-ph.png' }
];
user;
token;
name;
nickname;
constructor(private authenticationService: AuthenticationService,
private router: Router,
private http: Http,
private chatService: ChatService) { }
isLoggedIn() {
this.loading = true;
if (this.authenticationService.isAuthenticated()) {
return true;
}
}
gotoChat() {
this.chatService.gotoChat(this.user);
}
ngOnInit() {
}
}
The view for this component is looping through users (others) and displaying an icon for each "other" user. Here is that code:
<div *ngIf="isLoggedIn()" class="others">
<span *ngFor="let other of others"><i [ngClass]="'material-icons'" (click)="gotoChat()" [routerLink]="['/chat']">person</i></span>
<a [routerLink]="['/login']">Logout</a>
</div>
The ultimate goal here is for people to see others that are logged in, and be able to initiate a chat with them.
Where I'm stuck is in how to pass the value (this.model.username) that I'm capturing in the login component, down to the room component.
In the login method of your AuthenticationService you're storing the user object in local storage, you should also store it in the authentication service so that when it is injected into the component, you are able to access the user object.
You will need to add another method called getUsername to the AuthenticationService to get the username.
It will look something like this:
#Injectable()
export class AuthenticationService {
private username: string;
constructor(private http: Http) {}
login(username: string, password: string) {
return this.http.post('/api/authenticate', JSON.stringify({ username: username, password: password }))
.map((response: Response) => {
// login successful if there's a jwt token in the response
let user = response.json();
if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
// store username
this.username = user.username;
}
});
}
getUsername(): string {
return this.username;
}
make use of #input tag in angular2 this will help you pass information between components
Look at this link for ref
http://www.thoughtdelimited.org/thoughts/post.cfm/learning-angular-2-tour-of-heroes-tutorial-lesson-5
Related
I`m having problems understanding why I'm not able to set the user in the app. Register and login work.
Upon refreshing the app the user is lost, but the access token is still there. Also when I try to create a product, the manufacturer(owner) of it is undefined and not listed in the DB.
I've been debugging it and I can see that req.user is not found by the app and stays undefined/null.
I`m attaching the whole github project for easier code check, if someone decides to help me out here.
https://github.com/theBoomstick7/projectOils2
Thanks in advance everyone!
Changed all possible setting of the user, register and logout and login do work, but not the intended way.
I understand the design is not good, will be fixed later
As I understand this is not a good way to ask a question here, let me add some parts of the code.
This is the server controller of the product:
const {getAll,createProduct} = require(`../services/productService`)
const productController = require(`express`).Router()
productController.post(`/create`, async(req,res) => {
const data = req.body
console.log(req.user)
try {
const userId = req?.user?._id
const product = await createProduct(data,userId)
res.status(201).json(product)
} catch (error) {
res.status(400).json({error:error.message})
}
res.end()
})
This is the angular auth service :
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Router } from '#angular/router';
import { tap } from 'rxjs';
import { IUser } from '../interfaces/user';
const AUTH_API_URL = 'http://localhost:3000' // Change this to environment directory later
#Injectable({
providedIn: 'root'
})
export class AuthService {
user: null | IUser | undefined
constructor(private http: HttpClient, private router: Router) { }
get isLogged(): boolean {
if(this.user){
return true
}else
{
return false
}
}
register(data: {}){
return this.http.post<IUser>(`${AUTH_API_URL}/register`,data).pipe(
tap((user) => {
this.user = user
localStorage.setItem(`accessToken`, this.user.accessToken)
})
)
}
login(data: {}){
return this.http.post<IUser>(`${AUTH_API_URL}/login`, data). pipe(
tap((user) => {
this.user = user
localStorage.setItem(`accessToken`, this.user.accessToken)
})
)
}
logout(){
this.user = null
return localStorage.removeItem(`accessToken`)
}
}
This is the way the user register is handled :
export class RegisterComponent {
errors: any;
constructor(private fb: FormBuilder, private userService: AuthService, private router: Router) {}
registerForm = this.fb.group({
email: [``,[Validators.required, Validators.email]],
username: [``, [Validators.required, Validators.minLength(6)]],
password: [``, [Validators.required, Validators.minLength(6)]],
rePass: [``, [Validators.required,passwordValidator]]
})
register(): void{
this.userService.register(this.registerForm.value).subscribe
({
next: () => this.router.navigate([`/`]),
error:(err)=> {
this.errors = err.error?.error
}
})
this.registerForm.reset()
}
}
This is how a product is created
Product Angular service :
export class ProductsService {
constructor(private http : HttpClient, private router : Router) { }
createProduct(data : {}){
return this.http.post<IProduct>(`${API_URL}/create`, data)
}
}
Create product form :
import { Component } from '#angular/core';
import { FormBuilder, Validators } from '#angular/forms';
import { Route, Router } from '#angular/router';
import { ProductsService } from '../products.service'
#Component({
selector: 'app-create-product',
templateUrl: './create-product.component.html',
styleUrls: ['./create-product.component.css']
})
export class CreateProductComponent {
errors: string | undefined = undefined;
constructor(private fb : FormBuilder, private productService: ProductsService, private router : Router){}
createProductForm = this.fb.group({
title : [``, [Validators.required, Validators.maxLength(12)]],
imageUrl: [``, [ Validators.required]],
description: [``, [Validators.required, Validators.minLength(10)]]
})
createProduct(){
this.productService.createProduct(this.createProductForm.value).subscribe({
next: () => this.router.navigate([`/products`]),
error: (err) => {
this.errors = err.error?.error
}
})
this.createProductForm.reset()
}
}
I hope this makes it easier to everyone.
PP, this is my app interceptor :
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HTTP_INTERCEPTORS } from "#angular/common/http";
import { Injectable, Provider } from "#angular/core";
import { mergeMap, Observable, tap } from "rxjs";
#Injectable()
export class AppInterceptor implements HttpInterceptor{
accessToken:any | [] | null = localStorage.getItem(`accessToken`)
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>
{
if(this.accessToken)
{
return next.handle(req.clone({ setHeaders: {'X-Authorization' : this.accessToken}}))
}
else
{
return next.handle(req.clone())
}
}
}
export const AppInterceptorProvider: Provider = {
provide:HTTP_INTERCEPTORS,
useClass: AppInterceptor,
multi:true
}
I hope I understood well your question. If not, let me know. I will edit my answer.
I could debug your App.
You save your accessToken in the local storage, but not the User object. When you refresh the browser, the "accessToken" is there, but the user not because it was removed from the browser's memory.
In this case, your server knows that you are logged in, but your app (frontend) not.
In the auth.service.ts you have to save the user:
localStorage.setItem(`user`, JSON.stringify(this.user));
In the app.component.ts you have to load the user again and set it into the userService instance:
const myUser: string= localStorage.getItem('user') + '';
const loadedUser: IUser = JSON.parse(myUser);
console.log('Loaded User: ' + loadedUser)
this.userService.setLoggedUser(loadedUser);
An alternative solution could be check in the app.component.tsthe presence of the accessToken. If it is there, you can call a new REST method on the server to get the logged user for that token.
I use firebase and angularfire2 within an authentication system!
The problem is that after refresh the user needs to log in again! I need to avoid that issue so I found out that firebase gives me that option by using authState
but still not working!
This the code for the authService:
import { Injectable } from '#angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import { Observable } from 'rxjs/internal/observable';
import { NavController } from '#ionic/angular';
import { ToastMessagesService } from './toast-messages.service';
import * as firebase from 'firebase';
#Injectable({
providedIn: 'root'
})
export class AuthService {
public user: Observable<firebase.User>;
public userDetails: firebase.User = null;
constructor(
private af: AngularFireAuth,
private navCtrl: NavController,
private statusMessage: ToastMessagesService
) {
this.user = af.authState;
this.user.subscribe(
user => this.userDetails = user
)
}
async siginInRegular(username: string, password: string) {
try {
// const credentials = this.af.auth.email
return await this.af.auth.signInWithEmailAndPassword(username, password).then(
user => {
if (user) {
this.navCtrl.navigateForward('/home');
this.statusMessage.message(`Welcome ${user.user.email}`);
}
},
err => {
console.log(err);
}
);
} catch (error) {
console.dir(error);
}
}
async register(username: string, password: string) {
try {
return await this.af.auth.createUserWithEmailAndPassword(username, password).then(
user => {
this.navCtrl.navigateForward('/profile');
this.statusMessage.message(`Welcome ${user.user.email}`);
}
);
} catch (error) {
console.dir(error);
}
}
signOut() {
return this.af.auth.signOut();
}
isLoggedIn(): boolean {
return (this.userDetails != null) ? true : false;
}
}
The guard code:
import { Injectable } from '#angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '#angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
import { NavController } from '#ionic/angular';
import { AngularFireAuth } from 'angularfire2/auth';
#Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(
private auth: AuthService,
private navCtrl: NavController,
private af: AngularFireAuth
) {
}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if (this.auth.isLoggedIn()) {
return true
}
console.log('Access denied!');
return false;
}
}
Firebase actually automatically will sign the user in when you reload the page. But since your handling of the sign-in is only in the then() block, it only happens when you explicitly sign them in.
To fix this, you want to use an onAuthState listener as shown in get the currently signed in user:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
Unlike the then() handler, this onAuthStateChanged handler will be called every time the user's authentication state changes, including when you reload the page.
Since you're using AngularFire2, you can also use af.auth.subscribe as shown here: How to get the firebase.User in AngularFire2
i'm struggling to find a solution to this problem. I googled for hours but couldn't solve.
I need to change the menu item in my navbar template showing login vs logout when the user logs in and out.
I have 2 services, the authService which let the user login/logout and the sessionService which provides some basic functions to check if the session is set or not.
I want that every time i logIn or logout the user (so i update the localStorage in sessionService) my components which use this get updated too.
I tried with .subscribe, .map but cannot make this work. The only thing that make this work is call this.loggedIn.next(this._sessionService.isSetUserSession()); in login and logout methods.
Please, what am i doing wrong?
navbar.component.html
<div class="dropdown-menu" aria-labelledby="dropdownAccount">
<ng-template *ngIf="(loggedIn$ | async); else elseDiv;">
<a class="nav-link" href="javascript:void(0)" (click)="logout()">LOGOUT</a>
</ng-template>
<ng-template #elseDiv>
<a class="nav-link" href="javascript:void(0)"(click)="login(...);">
LOGIN
</a>
</ng-template>
</div>
navbar.component.ts
import {Component, OnInit} from '#angular/core';
import {AuthService} from '../services/auth.service';
#Component({
moduleId: module.id,
selector: 'app-nav-bar',
templateUrl: 'navbar.component.html',
styleUrls: ['./navbar.component.css'],
})
export class NavbarComponent implements OnInit {
isNavbarCollapsed = true;
loggedIn$: any;
constructor(
private authService: AuthService) {
}
ngOnInit() {
this.loggedIn$ = this.authService.isLoggedIn;
}
}
auth.service.ts
import {Injectable} from '#angular/core';
import {Http, Response} from '#angular/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/do';
import {IUser} from '../entities/user';
import {SessionService} from './session.service';
import {Router} from '#angular/router';
import {Subject} from 'rxjs/Subject';
#Injectable()
export class AuthService {
private loggedIn: Subject<boolean> = new Subject<boolean>();
get isLoggedIn() {
return this.loggedIn.asObservable();
}
constructor(private _http: Http,
private _sessionService: SessionService,
private _router: Router) {
this.loggedIn.next(this._sessionService.isSetUserSession());
}
login(user: IUser) {
return this._http.get('assets/api/responseSuccess.json?email=' + user.email + '&password=' + user.password)
.map((responseLogin => {
const jsonResponse = responseLogin.json();
if (jsonResponse.response === 'success') {
const userResponse: IUser = jsonResponse.user;
this._sessionService.setUserSession(userResponse);
//this.loggedIn.next(this._sessionService.isSetUserSession()); ==> This makes this works but i don't want fo call this every time i change the session, i just want that the session syncs automatically
return true;
} else {
console.log("error loggin in");
return false;
}
}));
}
logout() {
this._sessionService.clearUserSession();
// this.loggedIn.next(this._sessionService.isSetUserSession()); =>> Same here
return this._router.navigate(['/']);
}
}
session.service.ts
import {Injectable} from '#angular/core';
import {IUser} from '../entities/user';
import {isNullOrUndefined} from 'util';
import {Subject} from "rxjs/Subject";
#Injectable()
export class SessionService {
isSetUserSession(): boolean {
return !!localStorage.getItem('user');
}
clearUserSession() {
localStorage.removeItem('user');
}
setUserSession(user: IUser) {
localStorage.setItem('user', JSON.stringify(user));
}
}
This can be achieved without using subject instead use Shared service
Have the variable in service as below,
export class DataService {
isLoggedIn: boolean = false;
}
In the component get and set it as below,
get data():string {
return this.dataService.isLoggedIn;
}
set data(value: string) {
this.dataService.isLoggedIn = value;
}
Update 1 : Alternatively it can updated via another service also as below,
#Injectable()
export class AuthService {
constructor(public dataService: DataService) { }
update(value){
console.log(value)
this.dataService.isLoggedIn = value;
}
}
LIVE DEMO
Please make following changes.
Use BehaviorSubject instead of Subject.
A BehaviorSubject holds one value. When it is subscribed it emits the value immediately. A Subject doesn't hold a value. When you set the subject variable, it doesn't reflect in the nav component.
auth.service.ts
private loggedIn = new BehaviorSubject<boolean>(false);
get isLoggedIn() {
return this.loggedIn.asObservable();
}
Set the loggedIn variable in login and logout functions.
login(user: IUser) {
return this._http.get('assets/api/responseSuccess.json?email=' + user.email + '&password=' + user.password)
.map((responseLogin => {
const jsonResponse = responseLogin.json();
if (jsonResponse.response === 'success') {
const userResponse: IUser = jsonResponse.user;
this._sessionService.setUserSession(userResponse);
this.loggedIn.next(this._sessionService.isSetUserSession());
return true;
} else {
console.log("error loggin in");
return false;
}
}));
}
logout() {
this._sessionService.clearUserSession();
this.loggedIn.next(this._sessionService.isSetUserSession());
return this._router.navigate(['/']);
}
in navbar.component.ts
replace loggedIn$: any; by
isLoggedIn$: Observable<boolean>;
An explanation as follows.
The BehaviorSubject keeps the latest value cached which is set when user log ins or logs out. So when an Observer subscribes to the isLoggedIn(), the cached value is going to be emitted right away, depending on user is signed in or not.
This code will work for sure, as I am using in my current project.
I have two Component and one Service
Components:
1: LoginComponent
2: HeaderComponent (Shared)
Service:
1: authentication.service
In LoginComponent I use authentication.service to get authenticate and after successful authentication, I add User info into the Cookie and in the end, I automatically navigate to return-URL page, in the returned page I have a Component for the header that must show User info from the saved Cookie, BUT there is nothing in the cookie unless I refresh manually the page with F5 button.
My question is how can I access the cookie without refreshing the page?
Update
this is where I want to get the cookie:
import { Component, OnInit } from '#angular/core';
import { CookieHelper } from '../../_helpers/index';
#Component({
moduleId: module.id,
selector: 'app-header-ichart',
templateUrl: 'header.component.html',
styleUrls: ['header.component.css']
})
export class HeaderComponent implements OnInit {
currentUser = '';
isLogged = false;
constructor(private cookie: CookieHelper) { }
ngOnInit() {
this.isLogged = this.cookie.checkCookie('currentUser');
if (this.isLogged) {
this.currentUser = JSON.parse(this.cookie.getCookie('currentUser'));
}
}
}
Update 2
I used your suggestion technic to achieve my goal but need more help:
I Update my AuthenticationService to serve Observable Variable:
AuthenticationService:
import { Injectable } from '#angular/core';
import { Http, Headers, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/map';
import { AppConfig } from '../app.config';
import { CookieHelper } from '../_helpers/index';
#Injectable()
export class AuthenticationService {
cookies: Object;
keys: Array<string>;
user$ = new Subject<any>();
constructor(private http: Http, private config: AppConfig, private cookie: CookieHelper) { }
login(username: string, password: string) {
const headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
let body = `grant_type=${'password'}&username=${username}&password=${password}`;
return this.http.post(
this.config.apiUrl + '/token',
body, { headers: headers })
.map((response: Response) => {
// login successful if there's a jwt token in the response
let user = response.json();
if (user && user.access_token) {
user['username'] = username;
// Observable Variable
this.user$.next(JSON.stringify(user));
// store user details and jwt token in cookie to keep user logged in between page refreshes
this.cookie.addCookie('currentUser', JSON.stringify(user));
}
});
}
getUser(): Observable<any> {
return this.user$.asObservable();
}
logout() {
// remove user from cookie to log user out
this.cookie.removeCookie('currentUser');
// Logout Subscribe
this.user$.next(null);
}
}
HeaderComponent:
export class HeaderComponent implements OnInit {
currentUser = '';
isLogged = false;
constructor(private cookie: CookieHelper, private auth: AuthenticationService) { }
ngOnInit() {
// Get the currentUser from Observable Variable
this.auth.getUser().subscribe(currentUser => { this.currentUser = currentUser; });
console.log(this.currentUser);
this.isLogged = this.cookie.checkCookie('currentUser');
if (this.isLogged) {
this.currentUser = JSON.parse(this.cookie.getCookie('currentUser'));
}
}
}
I suggest to use an Observable to achieve that. So your headerComponent will be notified after the login.
Update your authentication.service so that you have something like
import { Subject } from 'rxjs/Subject';
export class AuthenticationService {
user$: Subject<any>;
login() {
// login stuff
this.user$.next('userDetails');
}
logout() {
this.user$.next(null);
}
}
and then from whatever component you want you can check for the user$ observable.
In template with
{{ (user$ | async)?.username }}
or in code with
user$.subscribe(user => console.log(user.username))
While making some edits to my Angular 2 app, I was able to get something working BEFORE I assumed it should be working. In other words, I'm a little perplexed as to why it's working in it's current configuration. Specifically, I have an authentication.service that handles my login auth. And I have both a login component and a chat component, both of which have a private instance of the authentication.service in their respective constructors. What I wanted to do was be able to pass the username from the login functionality down to the chat view, so I could display the logged-in user's username in the chatbox. I've got that working, but, strangely enough, I got it working by adding "this.authenticationService.username = this.model.username;" in the login.component, rather than in the authentication.service. So I'm perplexed as to how/why the chat.component even has access to that info. If I remove that one line of code from my login.component, the username will not be passed through to the chat.component. But I never actually import the login component into the chat component, so how is it working as is? Curious to see if someone can help me understand this. Here are the files in question. First, my authentication.service file:
import { ContextMenu } from './../ui/context-menu.component';
import { Router, RouterLinkActive } from '#angular/router';
import { Injectable } from '#angular/core';
import { Http, Headers, Response } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class AuthenticationService {
username;
constructor(private http: Http) {}
login(username: string, password: string) {
return this.http.post('/api/authenticate', JSON.stringify({ username: username, password: password }))
.map((response: Response) => {
// login successful if there's a jwt token in the response
let user = response.json();
if (user && user.token) {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('currentUser', JSON.stringify(user));
}
});
}
isAuthenticated() {
if (localStorage.getItem('currentUser')) {
//console.log('User successfully authenticated...');
return true;
} else {
// console.log('User is not authenticated...');
return false;
}
}
logout() {
// remove user from local storage to log user out
localStorage.removeItem('currentUser');
console.log('User successfully logged out');
}
}
And here's my login.component file:
import { UserService } from './../../data/user.service';
import { AuthenticationService } from './../../data/authentication.service';
import { AlertService } from './../../data/alert.service';
import { Component, OnInit, Input } from '#angular/core';
import { Router } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: 'app/views/login/login.component.html',
styleUrls: ['app/views/login/login.component.css']
})
export class LoginComponent implements OnInit {
model: any = {};
loading = false;
username;
password;
constructor(
private router: Router,
private authenticationService: AuthenticationService,
private alertService: AlertService,
private userService: UserService) { }
ngOnInit() {
// reset login status
this.authenticationService.logout();
}
login() {
this.loading = true;
this.authenticationService.login(this.model.username, this.model.password)
.subscribe(
data => {
this.router.navigate(['/']);
console.log('User logged in as: ' + this.model.username);
},
error => {
this.alertService.error(error);
this.loading = false;
});
this.authenticationService.username = this.model.username;
}
}
Here's my chat.component file:
import { AuthenticationService } from './../../data/authentication.service';
import { Router, ActivatedRoute } from '#angular/router';
import { ChatService } from './chat.service';
import { Component, OnInit, OnDestroy } from '#angular/core';
import { TabPage } from '../../ui/tab-navigation/tab-page';
#Component({
templateUrl: './chat.component.html',
styleUrls: ['./chat.component.less'],
})
export class ChatComponent extends TabPage implements OnInit, OnDestroy {
messages = [];
users = [];
routes;
connection;
userbase;
route;
message;
user;
constructor(private chatService:ChatService,
router: Router,
route: ActivatedRoute,
private authenticationService: AuthenticationService) {
super(router, route);
this._title = 'Chat Room';
this.addEventListener('paramsChange', function(params) {
this._title = 'Chat Room';
}.bind(this));
}
sendMessage() {
this.chatService.sendMessage(this.message);
this.message = '';
}
sendUser() {
this.chatService.sendUser(this.user);
this.user = '';
}
trackUser() {
this.chatService.trackUser(this.route);
console.log('A user just navigated to ' + this.route);
}
// For when user clicks "enter/return" to send message
eventHandler(event: KeyboardEvent): void {
if (event.key === 'Enter') {
this.chatService.sendMessage(this.message);
this.message = '';
}
}
ngOnInit() {
this.connection = this.chatService.getMessages().subscribe(message => {
this.messages.push(message);
});
this.userbase = this.chatService.getUsers().subscribe(user => {
this.users.push(user);
});
this.routes = this.chatService.getRoutes().subscribe(route => {
this.routes.push(route);
});
}
ngOnDestroy() {
this.connection.unsubscribe();
this.userbase.unsubscribe();
}
public getTabId(params): string {
return 'Chat Room';
}
}
Lastly, my chat.component.html file looks like this (this is where I'm actually using the string interpolation to display the username in the chat):
<div class="centered-display" align="center">
<h3>User: {{authenticationService.username}}</h3>
<div *ngFor="let message of messages" class="message">
{{authenticationService.username}}: {{message.text}}
</div>
<input class="form-group" [(ngModel)]="message" (keypress)="eventHandler($event)">
<div class="spacing">
<button class="submit-btn" md-button (click)="sendMessage()">SEND</button>
</div>
</div>
Can someone help me understand why this is working as is? The one line that makes this work is the last line in my login.component login function: "this.authenticationService.username = this.model.username;". But, again, my chat component doesn't have access to my login component (as as I understand). So why is this working?
Your chat component and login component may not directly relate to each other, but they do both have access to the authenticationService. Specifically, they both have a reference to the same instance of that service injected.
This means that when you do this.authenticationService.username = this.model.username in your login component, you are setting the username property on the same authenticationService object that you are accessing with your interpolation in the chat component view ({{authenticationService.username}}).