问题
Note: I'm new to all of this, please excuse what might be obvious. Any help is massively appreciated :)
What I have
- An auth service to log in and out
- An album service to fetch items based on user id
- albumList > UserId > albumKey
- In my album list service I query the path 'albumList > userId'
- Once I log in, this works perfectly, and only the results based on the matched query of the above are returned
Issues
- If I were to copy and paste the URL of 'localhost:4200/albums' into another tab, the console reads
Uncaught (in promise): TypeError: Cannot read property 'uid' of null
- As a result, nothing loads and the URL pasted isn't maintained
Questions
- Do I need to add a user observable in all my components?
- How do I ensure that the user state is checked before loading my data?
- Is it possible to just use my Auth.Service as a reference point for all other components?
My Auth Service
import { Injectable } from '@angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase/app';
import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class AuthService {
user: Observable<firebase.User>;
constructor(
private firebaseAuth: AngularFireAuth,
private router: Router) {
this.user = firebaseAuth.authState;
}
login(email: string, password: string) {
this.firebaseAuth
.auth
.signInWithEmailAndPassword(email, password)
.then(value => {
console.log('Nice, it worked!');
console.log(this.firebaseAuth.auth.currentUser.uid);
this.router.navigate(['/albums'])
})
.catch(err => {
console.log('Something went wrong:', err.message);
});
}
logout() {
this.firebaseAuth
.auth
.signOut();
}
}
My Album List Service
note: If i remove the albumList query with the user id on the end (commented out query), I can copy and paste the URL into a new tab and the URL is maintained (url.com/albums). However, any data won't be filtered by the user key first.
import { Injectable } from '@angular/core';
import { AngularFireDatabase, FirebaseListObservable, FirebaseObjectObservable } from 'angularfire2/database';
import { AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase/app';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class ProjectsListService {
albumList: FirebaseListObservable<any[]>;
user: Observable<firebase.User>;
constructor(
private database: AngularFireDatabase,
private firebaseAuth: AngularFireAuth) {
//this.albumList = database.list('/albumList');
this.albumList = database.list('/albumList/' + this.firebaseAuth.auth.currentUser.uid);
//console.log(this.firebaseAuth.auth.currentUser.uid);
}
getAlbumList() {
return this.albumList;
}
}
回答1:
Questions
- Do I need to add a user observable in all my components?
Yes, you are working with async data all the time, you need to subscribe to the changes coming from the firebase
- How do I ensure that the user state is checked before loading my data?
It seems that you are also relatively new to angular, it might be harder for you to learn everything at once. You should check the Router tutorial, more exactly the module 5 Route Guards.
- Is it possible to just use my Auth.Service as a reference point for all other components?
Yes, that's entirely up to you and it's a very common thing.
As for the Type error, you are trying to accessing a value that doesn't exist when you initialize your app, since you get that asynchronously you need to subscribe to the authState
import { Injectable } from '@angular/core';
import { AngularFireDatabase, FirebaseListObservable, FirebaseObjectObservable } from 'angularfire2/database';
import { AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase/app';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class ProjectsListService {
albumList: FirebaseListObservable<any[]>;
user: Observable<firebase.User>;
constructor(
private database: AngularFireDatabase,
private firebaseAuth: AngularFireAuth
) {
firebaseAuth.authState.subscribe(user => {
console.log(user);
if (user) {
this.albumList = database.list('/albumList/' + user.uid);
}
})
}
getAlbumList() {
return this.albumList;
}
}
Edit
The previous code didn't work, because when you first run your app, the albumList is an empty var, that's why after you navigate everything works fine, because after that it's already initialised and you can subscribe to it.
So because you depend on the auth state you should be subscribing to your albumList
on your components instead. Why? Because if your user for some reason logs out, you also hide the information.
So instead of using ProjectsListService
on your component you will do something like this:
import { Component } from '@angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import { AngularFireDatabase, FirebaseListObservable } from 'angularfire2/database'
@Component({
selector: 'your-component',
template: `<ul><li *ngFor="let album of albumList | async">{{ todo.text }}</li></ul>`
})
export class YOURComponent {
albumList: FirebaseListObservable<any[]>;
constructor(
private fAuth: AngularFireAuth,
private database: AngularFireDatabase
) {
fAuth.authState.subscribe(user => {
if (user) {
this.albumList = database.list('/albumList/' + user.uid);
return;
}
this.albumList = null;
})
}
}
来源:https://stackoverflow.com/questions/44928646/angularfire-firebase-checking-the-authentication-state