ERROR TypeError: You provided 'null' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable
ERROR TypeError: You provided 'null' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable
我到处寻找答案,但我无法解决这个问题。
我发现很多人在 Angular 中遇到 Observables 的这个问题,但通常这只是一个语法错误。我尝试了很多东西(我将在下面列出)但我很困惑。不知道为什么会这样
错误:
ERROR TypeError: You provided 'null' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
这不是功能性错误。事实上,它完全符合我的期望,但它会向控制台抛出一个错误。
预期:
它只是管理菜单内容视图的 ngIf 指令。如果用户登录,它应该查看某些菜单项(例如 'My profile',等等),如果没有,它应该只看到 'Login' 和 'Signup' 按钮。它实际上适用于这种系统,但我收到控制台错误。
我尝试了什么:
谷歌搜索我尝试了很多东西。下面列出的只是其中的一小部分,但在某些时候我只是在尝试而不真正知道如何解决问题。
在第一次尝试中(我不会在这里列出,因为它很长),我尝试切换映射 angular 触发身份验证状态以获取登录状态,然后我设置 this.appUser $从数据库到this.userService.get(user.uid),到return用户数据。这将是最终结果,但在得到错误后我简化了很多代码以找出问题所在,希望它更容易。事实上,我试了3天也没有解决任何问题。
-
navbar.component.html
<mat-menu #userMenu="matMenu">
<ng-template matMenuContent >
<div class="menuContent" *ngIf="(appUser$ | async) as user; else notLoggedMenuitems">
<div mat-menu-item>
<div class="row no-gutters ml-2 mr-2">
<div class="col-auto"><img [src]="user.photoURL" class="user-profile-img" alt="Profile image"></div>
<div class="col"><p class="mat-body-strong mb-0 ml-3" style="line-height: 350%;"><b>{{ user.displayName }}</b></p></div>
</div>
</div>
<mat-divider class="mt-2"></mat-divider>
<div mat-menu-item>...</div>
<div mat-menu-item>...</div>
<mat-divider></mat-divider>
<div mat-menu-item (click)="logout()">Logout</div>
</div>
<ng-template #notLoggedMenuitems>
<div mat-menu-item routerLink="/auth/login">Login</div>
<div mat-menu-item routerLink="/auth/signup">Signup</div>
</ng-template>
</ng-template>
</mat-menu>
-
navbar.component.ts
export class NavbarComponent implements OnInit {
appUser$: Observable<firebase.User>;
constructor(private auth: AngularFireAuth) {
this.appUser$ = this.auth.user;
}
ngOnInit(): any {
}
logout(): void {
this.auth.signOut();
}
}
-
navbar.component.html
I changed the ngIf directive to the one below, removing the else block. I tried even with other operators like " ! " and so on, but nothing changed...
*ngIf="(appUser$ | async)"
-
navbar.component.ts
export class NavbarComponent implements OnInit {
appUser$: Observable<firebase.User> = this.auth.user;
constructor(private auth: AngularFireAuth) {}
ngOnInit(): any {
}
logout(): void {
this.auth.signOut();
}
}
结论:
我怎样才能做到这一点?我不知道为什么打字稿会抛出这个错误。
更新 1:
已更新 navbar.component.html
<mat-menu #userMenu="matMenu">
<ng-template matMenuContent >
<div class="menuContent" *ngIf="(appUser$ | async) as user; else notLoggedMenuitems">
<div mat-menu-item>
<div class="row no-gutters ml-2 mr-2">
<div class="col-auto"><img [src]="user.details.imgUrl" class="user-profile-img" alt="Profile image"></div>
<div class="col"><p class="mat-body-strong mb-0 ml-3" style="line-height: 350%;"><b>{{ user.name }}</b></p></div>
</div>
</div>
<mat-divider class="mt-2"></mat-divider>
<ng-container *ngIf="user.roles.admin">
<div mat-menu-item><mat-icon>local_bar</mat-icon>Manage Drinks</div>
<div mat-menu-item><mat-icon>note_add</mat-icon>Add Drinks</div>
<mat-divider></mat-divider>
</ng-container>
<div mat-menu-item><mat-icon>settings</mat-icon>My Profile</div>
<div mat-menu-item><mat-icon>wine_bar</mat-icon>My Drinks</div>
<div mat-menu-item><mat-icon>favorite</mat-icon>Wishlist</div>
<mat-divider></mat-divider>
<div mat-menu-item (click)="logout()">Logout</div>
</div>
<ng-template #notLoggedMenuitems>
<div mat-menu-item routerLink="/auth/login">Login</div>
<div mat-menu-item routerLink="/auth/signup">Signup</div>
</ng-template>
</ng-template>
</mat-menu>
已更新navbar.component.ts
import { Component, OnInit } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/auth';
import { Observable } from 'rxjs';
import { AuthenticationService } from './../../../auth/authentication/authentication.service';
import { User } from './../../../auth/authentication/models/user.model';
@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss']
})
export class NavbarComponent implements OnInit {
appUser$: Observable<User>;
constructor(private authService: AuthenticationService, private auth: AngularFireAuth) {
}
ngOnInit(): any {
this.appUser$ = this.authService.user$;
this.appUser$.subscribe(res => console.log('in app user: ', res));
}
logout(): void {
this.auth.signOut();
}
}
已更新authentication.service.ts
private initUser(): void {
this.user$ = this.afAuth.authState.pipe(
switchMap(user => {
if (user) {
return this.db.doc$<User>(`users/${user.uid}`);
} else {
return undefined;
}
})
);
}
更新 2:
已更新 authentication.service.ts
private initUser(): void {
this.user$ = this.afAuth.authState.pipe(
switchMap(user => {
if (user) {
return this.db.doc$<User>(`users/${user.uid}`);
} else {
return new Observable<User>();
}
})
);
}
现在我看不到错误了。但是用户图片显示的不是很好...不过我不知道这是否是个好方法。
我想你差不多明白了。
不正确的是您在服务中处理 user$ 的方式。您应该始终 return switchMap 运算符中的可观察对象。
要处理没有用户登录的情况,您可以使用 of()
。它是一个 Observable,它发出参数中传递的值并在之后立即完成。
关于您使用的数据库,您使用的是 firestore 还是实时数据库?
在这两种情况下,要请求您的数据,您都需要使用 valueChanges 结束对 return observable 的调用。
我假设您使用的是 firestore,因为您调用了 doc 方法:
private initUser(): void {
this.user$ = this.afAuth.authState.pipe(
switchMap(user => {
if (user) {
// return an observable<User>
return this.db.doc<User>(`users/${user.uid}`).valueChanges();
} else {
return of(null);
}
})
);
}
试试这个,它应该有效。
我到处寻找答案,但我无法解决这个问题。 我发现很多人在 Angular 中遇到 Observables 的这个问题,但通常这只是一个语法错误。我尝试了很多东西(我将在下面列出)但我很困惑。不知道为什么会这样
错误:
ERROR TypeError: You provided 'null' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
这不是功能性错误。事实上,它完全符合我的期望,但它会向控制台抛出一个错误。
预期:
它只是管理菜单内容视图的 ngIf 指令。如果用户登录,它应该查看某些菜单项(例如 'My profile',等等),如果没有,它应该只看到 'Login' 和 'Signup' 按钮。它实际上适用于这种系统,但我收到控制台错误。
我尝试了什么:
谷歌搜索我尝试了很多东西。下面列出的只是其中的一小部分,但在某些时候我只是在尝试而不真正知道如何解决问题。
在第一次尝试中(我不会在这里列出,因为它很长),我尝试切换映射 angular 触发身份验证状态以获取登录状态,然后我设置 this.appUser $从数据库到this.userService.get(user.uid),到return用户数据。这将是最终结果,但在得到错误后我简化了很多代码以找出问题所在,希望它更容易。事实上,我试了3天也没有解决任何问题。
-
navbar.component.html
<mat-menu #userMenu="matMenu">
<ng-template matMenuContent >
<div class="menuContent" *ngIf="(appUser$ | async) as user; else notLoggedMenuitems">
<div mat-menu-item>
<div class="row no-gutters ml-2 mr-2">
<div class="col-auto"><img [src]="user.photoURL" class="user-profile-img" alt="Profile image"></div>
<div class="col"><p class="mat-body-strong mb-0 ml-3" style="line-height: 350%;"><b>{{ user.displayName }}</b></p></div>
</div>
</div>
<mat-divider class="mt-2"></mat-divider>
<div mat-menu-item>...</div>
<div mat-menu-item>...</div>
<mat-divider></mat-divider>
<div mat-menu-item (click)="logout()">Logout</div>
</div>
<ng-template #notLoggedMenuitems>
<div mat-menu-item routerLink="/auth/login">Login</div>
<div mat-menu-item routerLink="/auth/signup">Signup</div>
</ng-template>
</ng-template>
</mat-menu>
-
navbar.component.ts
export class NavbarComponent implements OnInit {
appUser$: Observable<firebase.User>;
constructor(private auth: AngularFireAuth) {
this.appUser$ = this.auth.user;
}
ngOnInit(): any {
}
logout(): void {
this.auth.signOut();
}
}
-
navbar.component.html
I changed the ngIf directive to the one below, removing the else block. I tried even with other operators like " ! " and so on, but nothing changed...
*ngIf="(appUser$ | async)"
-
navbar.component.ts
export class NavbarComponent implements OnInit {
appUser$: Observable<firebase.User> = this.auth.user;
constructor(private auth: AngularFireAuth) {}
ngOnInit(): any {
}
logout(): void {
this.auth.signOut();
}
}
结论:
我怎样才能做到这一点?我不知道为什么打字稿会抛出这个错误。
更新 1:
已更新 navbar.component.html
<mat-menu #userMenu="matMenu">
<ng-template matMenuContent >
<div class="menuContent" *ngIf="(appUser$ | async) as user; else notLoggedMenuitems">
<div mat-menu-item>
<div class="row no-gutters ml-2 mr-2">
<div class="col-auto"><img [src]="user.details.imgUrl" class="user-profile-img" alt="Profile image"></div>
<div class="col"><p class="mat-body-strong mb-0 ml-3" style="line-height: 350%;"><b>{{ user.name }}</b></p></div>
</div>
</div>
<mat-divider class="mt-2"></mat-divider>
<ng-container *ngIf="user.roles.admin">
<div mat-menu-item><mat-icon>local_bar</mat-icon>Manage Drinks</div>
<div mat-menu-item><mat-icon>note_add</mat-icon>Add Drinks</div>
<mat-divider></mat-divider>
</ng-container>
<div mat-menu-item><mat-icon>settings</mat-icon>My Profile</div>
<div mat-menu-item><mat-icon>wine_bar</mat-icon>My Drinks</div>
<div mat-menu-item><mat-icon>favorite</mat-icon>Wishlist</div>
<mat-divider></mat-divider>
<div mat-menu-item (click)="logout()">Logout</div>
</div>
<ng-template #notLoggedMenuitems>
<div mat-menu-item routerLink="/auth/login">Login</div>
<div mat-menu-item routerLink="/auth/signup">Signup</div>
</ng-template>
</ng-template>
</mat-menu>
已更新navbar.component.ts
import { Component, OnInit } from '@angular/core';
import { AngularFireAuth } from '@angular/fire/auth';
import { Observable } from 'rxjs';
import { AuthenticationService } from './../../../auth/authentication/authentication.service';
import { User } from './../../../auth/authentication/models/user.model';
@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss']
})
export class NavbarComponent implements OnInit {
appUser$: Observable<User>;
constructor(private authService: AuthenticationService, private auth: AngularFireAuth) {
}
ngOnInit(): any {
this.appUser$ = this.authService.user$;
this.appUser$.subscribe(res => console.log('in app user: ', res));
}
logout(): void {
this.auth.signOut();
}
}
已更新authentication.service.ts
private initUser(): void {
this.user$ = this.afAuth.authState.pipe(
switchMap(user => {
if (user) {
return this.db.doc$<User>(`users/${user.uid}`);
} else {
return undefined;
}
})
);
}
更新 2:
已更新 authentication.service.ts
private initUser(): void {
this.user$ = this.afAuth.authState.pipe(
switchMap(user => {
if (user) {
return this.db.doc$<User>(`users/${user.uid}`);
} else {
return new Observable<User>();
}
})
);
}
现在我看不到错误了。但是用户图片显示的不是很好...不过我不知道这是否是个好方法。
我想你差不多明白了。
不正确的是您在服务中处理 user$ 的方式。您应该始终 return switchMap 运算符中的可观察对象。
要处理没有用户登录的情况,您可以使用 of()
。它是一个 Observable,它发出参数中传递的值并在之后立即完成。
关于您使用的数据库,您使用的是 firestore 还是实时数据库?
在这两种情况下,要请求您的数据,您都需要使用 valueChanges 结束对 return observable 的调用。
我假设您使用的是 firestore,因为您调用了 doc 方法:
private initUser(): void {
this.user$ = this.afAuth.authState.pipe(
switchMap(user => {
if (user) {
// return an observable<User>
return this.db.doc<User>(`users/${user.uid}`).valueChanges();
} else {
return of(null);
}
})
);
}
试试这个,它应该有效。