typescript - No se obtiene el ID al iniciar sesión antes de actualizar la página - Angular
Estoy trabajando en mi proyecto de Angular y tengo este error donde no obtengo mi authService.currentUserId que uso para buscar en mis colecciones de Firebase Firestore, cuando navego a las páginas por primera vez después de iniciar sesión.
Tengo que actualizar la página para que funcione y luego no vuelvo a recibir el error. Este error no ocurre cuando uso mi función registerWithEmail y cargo la página, pero sí ocurre con mi función loginWithEmail.
auth.Service.ts
import {Injectable} from '@angular/core';
import {AngularFireAuth} from '@angular/fire/auth';
import {Router} from '@angular/router';
import {AngularFirestore} from '@angular/fire/firestore';
import {CompanyUserInterface} from '../../models/companyuser';
@Injectable({
providedIn: 'root'
})
export class AuthService {
authState: any = null;
constructor(private afAuth: AngularFireAuth, private router: Router, public fireService: AngularFirestore) {
this.afAuth.authState.subscribe((auth => {
this.authState = auth;
}));
}
// is called when company register. creates firebase auth login with email and password
// this also creates a document with the information from the registration in the collection companies
registerWithEmail(email: string, password: string, companyUser: CompanyUserInterface) {
console.log(email, password);
return this.afAuth.createUserWithEmailAndPassword(email, password).then((data) => {
console.log('reg email', data);
this.authState = data;
// Gets user id and added to company for unique id
companyUser.UID = data.user.uid;
return this.fireService.collection('companies').add(Object.assign({}, companyUser));
}).catch(error => {
console.log(error);
throw error;
});
}
// is called in login and checks if login info is correct in firebase
loginWithEmail(email: string, password: string) {
return this.afAuth.signInWithEmailAndPassword(email, password).then((data) => {
this.authState = data;
})
.catch(error => {
console.log(error);
throw error;
});
}
logout(): void {
this.afAuth.signOut().then();
this.router.navigate(['/login']).then();
}
// all firebase getter functions
get isUserAnonymousLoggedIn(): boolean {
return (this.authState !== null) ? this.authState.isAnonymous : false;
}
get currentUserId(): string {
return (this.authState !== null) ? this.authState.uid : '';
}
get currentUserName(): string {
return this.authState.email;
}
get currentUser(): any {
return (this.authState !== null) ? this.authState : null;
}
get isUserEmailLoggedIn(): boolean {
return (this.authState !== null) && (!this.isUserAnonymousLoggedIn);
}
}
login.componentes.ts
import {Component, OnInit} from '@angular/core';
import {AuthService} from '../../services/auth/auth.service';
import {Router} from '@angular/router';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
email = '';
password = '';
errorMessage = ''; // validation error handling
error: { name: string, message: string } = {name: '', message: ''}; // for firebase error handling
constructor(private authService: AuthService, private router: Router) {
}
ngOnInit(): void {
}
// checks with firebase is user info is inputted and then if its valid. routes to userinfo site
login() {
this.clearErrorMessage();
if (this.validateForm(this.email, this.password)) {
this.authService.loginWithEmail(this.email, this.password).then(() => {
this.router.navigate(['schedule']).then();
}).catch(error => {
this.error = error;
this.router.navigate(['login']).then();
});
}
}
}
register.components.ts
import {Component, OnInit} from '@angular/core';
import {AuthService} from '../../services/auth/auth.service';
import {Router} from '@angular/router';
import {NgbModal, NgbModalConfig} from '@ng-bootstrap/ng-bootstrap';
import {CompanyUserInterface, CompanyUser} from '../../models/companyuser';
@Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.css']
})
export class RegisterComponent implements OnInit {
companyUser: CompanyUserInterface;
password = '';
message = '';
errorMessage = ''; // validation error handling
error: { name: string, message: string } = {name: '', message: ''}; // for firebase error handling
constructor(public authService: AuthService,
private router: Router,
private config: NgbModalConfig,
private modalService: NgbModal,
) {
// customize default values of modals used by this component tree
config.backdrop = 'static';
config.keyboard = false;
this.companyUser = new CompanyUser('', '', '', '', '');
}
ngOnInit(): void {
}
// register company/association. checks if value are true before creating with authService
// sends company info from registry to create new doc in collection
registerWithEmail(content) {
this.clearErrorMessage();
console.log(this.companyUser);
if (this.validateRegisterForm(this.companyUser.email, this.password)) {
this.authService.registerWithEmail(this.companyUser.email, this.password, this.companyUser).then(() => {
this.modalService.open(content);
this.router.navigate(['userinfo']).then();
this.message = '\nCongratulations on creating your profile\n'.toUpperCase();
}).catch(error => {
this.error = error;
this.router.navigate(['register']).then();
});
}
}
}
schedule.service.ts
import {Injectable} from '@angular/core';
import {AngularFirestore, AngularFirestoreCollection, AngularFirestoreDocument} from '@angular/fire/firestore';
import {ScheduleInterface} from '../../models/schedule';
import {Observable} from 'rxjs';
import {map} from 'rxjs/operators';
import {AuthService} from '../auth/auth.service';
@Injectable({
providedIn: 'root'
})
export class ScheduleService {
schedulesCollection: AngularFirestoreCollection<ScheduleInterface>;
schedules: Observable<ScheduleInterface[]>;
scheduleDoc: AngularFirestoreDocument<ScheduleInterface>;
constructor(private afs: AngularFirestore, public authService: AuthService) {
}
getSchedules(): Observable<ScheduleInterface[]> {
// I'm not getting my authService currentUserId on the first call.
console.log('test in getSchedules', this.authService.currentUserId);
return this.afs.collection('schedules', (ref) => ref
.where('UID', '==', this.authService.currentUserId)
.orderBy('user', 'asc'))
.snapshotChanges()
.pipe(
map((changes) =>
changes.map((a) => {
const data = a.payload.doc.data() as ScheduleInterface;
data.docRef = a.payload.doc.id;
return data;
})
)
);
}
}
Respuesta #1
No veo ScheduleService inyectado en ningún componente. Necesitas inyectar ese servicio para poder usarlo y hacerlo después de AuthService, ya que el servicio de autenticación se inyecta en ScheduleService. AuthService debería inicializarse antes que ScheduleService.
Respuesta #2
Asumiendo que estás utilizando inyección de dependencias estándar, se instancia una nueva instancia de tu servicio cada vez, por lo que un campo en la clase del servicio no se almacenará, como authState.
Utiliza el almacenamiento local o el almacenamiento de sesión para guardar estos datos. Como ejemplo,
Para ahorrar:
loginWithEmail(email: string, password: string) {
return this.afAuth.signInWithEmailAndPassword(email, password).then((data) => {
// this.authState = data;
// uid is the variable containing your value to save
localStorage.setItem('uid', data.uid);
// If you want to use the sessionStorage
// sessionStorage.setItem('uid', data.uid);
})
.catch(error => {
console.log(error);
throw error;
});
}
Para cargar:
getSchedules(): Observable<ScheduleInterface[]> {
return this.afs.collection('schedules', (ref) => ref
.where('UID', '==', localStorage.getItem('uid')) // <--- Here
.orderBy('user', 'asc'))
.snapshotChanges()
.pipe(
map((changes) =>
changes.map((a) => {
const data = a.payload.doc.data() as ScheduleInterface;
data.docRef = a.payload.doc.id;
return data;
})
)
);
}
Y cuando el usuario cierre sesión, asegúrese de borrar todas las claves (o las claves que desee).
Para eliminar un elemento de localStorage, utiliza
localStorage.removeItem("uid");
Para limpiar el almacenamiento local, es decir, vaciarlo (eliminar todas las claves almacenadas en el almacenamiento local)
localStorage.clear();
