I'm trying to set the token
attribute on my AuthenticationService
.
Here's my code:
authentication.service.ts
import { Injectable } from '@angular/core'
import { Http, Headers, Response } from '@angular/http'
import { Observable, BehaviorSubject } from 'rxjs'
import 'rxjs/add/operator/map'
import { Login } from '../../+authentication/shared/models'
import { config } from '../config'
@Injectable()
export class AuthenticationService {
private token: string
private _isConnected = new BehaviorSubject<boolean>(false)
isConnected$ = this._isConnected.asObservable()
constructor (private http: Http) {
const currentToken = JSON.parse(localStorage.getItem('currentToken'))
if (currentToken) {
this.token = currentToken.token
this._isConnected.next(true) // work
}
}
login (login: Login): Observable<any> {
return this.http.post(config.BASE_URL + '/auth/login', login)
.map((response: Response) => {
if (response.json() && response.json().success) {
const token = response.json() && response.json().token
this.token = token// don't do the work
this._isConnected.next(true) // don't do the work neither
localStorage.setItem('currentToken', JSON.stringify({token}))
return {
success: true
}
} else if (response.json() && response.json().message) {
return {
success: false,
message: response.json().message
}
}
})
}
logout (): void {
this.token = null
this._isConnected.next(false) // work
localStorage.removeItem('currentToken') // work
}
logToken (): void {
console.log(this.token) // null
console.log(localStorage.getItem('currentToken')) // {"token":"eyJhb..."}
// do the work
this.token = localStorage.getItem('currentToken')
console.log(this.token)
// do the work too
this._isConnected.next(true)
}
}
Called from login.component.ts
import { Component, OnInit } from '@angular/core'
import { Router } from '@angular/router'
import { AuthenticationService } from '../../shared/services'
import { Login } from '../shared/models/index'
@Component({
selector: 'login',
templateUrl: './login.component.html',
})
export class LoginComponent {
public login: Login = new Login('test@test.fr', 'test')
public authError: string
constructor (
private router: Router,
private as: AuthenticationService
) {
if (as.getToken()) {
this.router.navigate(['/home']) // This work !! That's not
}
}
onSubmit () {
this.as.login(this.login)
.subscribe((result) => {
if (result.success) {
this.router.navigate(['/home']) // working
} else if (result.message) {
this.authError = result.message // working
}
})
}
}
At the end of authentication.service.ts
, you can see the logToken
function:
logToken (): void {
console.log(this.token) // null
console.log(localStorage.getItem('currentToken')) // {"token":"eyJhb..."}
// do the work
this.token = localStorage.getItem('currentToken')
console.log(this.token)
// do the work too
this._isConnected.next(true)
}
I call it manually from my app component by clicking a button in the navbar, and the token property is never set, unless I reload the page, in that case it's set by the constructor of the service, who gets it from LocalStorage.
Please tell me why the let don't want to work, I used the arrow-function to bind it but it seems it's not working.
Thanks in advance
SherlockStd
EDIT
I tried to delegate the response handling to a private method to see if the this binding is better, but it's still not working (authentication.service.ts):
login (login: Login): Observable<any> {
return this.http.post(config.BASE_URL + '/auth/login', login)
.map((response: Response) => this.handleResponse(response))
}
private handleResponse (response: Response) {
if (response.json() && response.json().success) {
// login successful if there's a jwt token in the response
const token = response.json() && response.json().token
this.token = token
localStorage.setItem('currentToken', JSON.stringify({token}))
return {
success: true
}
} else if (response.json() && response.json().message) {
return {
success: false,
message: response.json().message
}
}
}
EDIT 2
I logged the this
keyword from authentication.service.ts, inside the login()
and logToken()
functions.
It return an AuthenticationService each times, containing the same attributes but into the login function it contains the token
attribute, which is lossed outside this function.
After 3 days of research, I finally found the source of this problem.
I was declaring the same service in the parent (app.module.ts
) and the child (authentication.module.ts
) modules (see the structure below).
src/
├── app.component.html
├── app.component.ts
├── app.module.ts <== provide AuthenticationService
├── app.routes.ts <== load authentication.module with router.loadChildren()
│
├── +authentication/
│ ├── authentication.component.html
│ ├── authentication.component.ts
│ ├── authentication.module.ts <== provide AuthenticationService
│ ├── authentication.routes.ts <== expose a route to login component
│ └── login
│ ├── login.component.html
│ └── login.component.ts <== using service's methods here don't work
│
└── shared/
└── services/
├── authentication.service.ts
└── base.service.ts
I can't understand why it influenced the this
binding, but it's working now, and I opened an issue on Github because I think an error should throw up in that case.
Thanks for your help.