【问题标题】:Cannot read property 'subscribe' of undefined using Angular and RxJs无法使用 Angular 和 RxJs 读取未定义的属性“订阅”
【发布时间】:2021-05-21 11:35:46
【问题描述】:

我有一个 Angular 应用程序,其中包含一个 UserService 和一个守卫。该守卫正在使用 UserService 创建一个用户,并根据其角色使用该用户来决定返回 true 或 false。见以下代码:

这是警卫:

  canActivate(): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

  return new Observable<boolean>(obs => {
    this.userService.getUser().subscribe(user => {
      if (user.roles.includes(Roles.IT_PROFESSIONAL)) {
        obs.next(true);
      } else {
        this.router.navigate(['/']);
        obs.next(false);
      }
    });
  });
}

这是 UserService 类:

  private static user: User;

  public getUser(): Observable<User> {

    if (!UserService.user) {

        UserService.user = new User();
        this.getGroups()
        .subscribe((response: any) => {
          response.value.map((v: any) => {  
            this.setRol(v); // use v to push v to the role array of the user
          });

          return of(UserService.user);
        });
    }
    else{
      return of(UserService.user);
    }
  }

    private getGroups(): Observable<any> { // Get groups for user
      return this.http.get("https://graph.microsoft.com/v1.0/me/memberOf");
    }

当我运行应用程序时,它显示“无法读取未定义的属性‘订阅’”。问题是守卫订阅了 getUser observable,但这让我立即获得了用户 observable。为什么不等待UserService返回用户返回“(UserService.user)”语句?

【问题讨论】:

  • 感谢您的回答!现在它在 setRole 方法中说“无法设置未定义的属性'角色'”,它基本上是这样做的:“ if(v.mailNickname == "Employees") { UserService.user.roles = [Roles.IT_PROFESSIONAL]; }"

标签: angular typescript events rxjs


【解决方案1】:

我认为在这两种情况下都不需要订阅 observable。您可以使用map 修改通知或使用tap 运算符执行副作用并简单地转发observable。试试下面的

守卫

canActivate(): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
  return this.userService.getUser().map(user => {
    if (user.roles.includes(Roles.IT_PROFESSIONAL)) {
      return true;
    }
    this.router.navigate(['/']);
    return false;
  });
}

用户类服务

public getUser(): Observable<User> {
  return (!!UserService.user)
    ? of(UserService.user)
    : this.getGroups().pipe(
        map((response: any) => // <-- not sure if `response` is modified here, if not use `tap`
          response.value.map((v: any) => this.setRol(v))
        )
      );
}

更新:初始化UserService.user

private static user: User;    // <-- don't initialize here
public getUser(): Observable<User> {
  return (!!UserService.user)
    ? of(UserService.user)
    : this.getGroups().pipe(
        tap((response: any) =>
          response.value.forEach((v: any) => this.setRol(v))
        )
      );
}

setRol(v: any) {
  if (!UserService.user) UserService.user = { /* valid user object */ } // <-- initialize here
  if (v.mailNickname == "Employees")  { 
    UserService.user.roles = [Roles.IT_PROFESSIONAL]; 
  }
}

【讨论】:

  • 感谢您的回答!现在它在 setRole 方法中说“无法设置未定义的属性'角色'”,它基本上是这样做的:“ if(v.mailNickname == "Employees") { UserService.user.roles = [Roles.IT_PROFESSIONAL]; }"
  • 您只定义了变量user。您需要初始化它才能使用它:例如。 private static user: User = Object.create(null).
  • 顺便说一句,如果您在应用程序的其他地方使用此静态属性,最好将其定义为多播 observable。例如。 user: ReplaySubject&lt;User&gt; = new ReplaySubject&lt;User&gt;(1)。这样你就可以保持数据的反应性。
  • 无法读取未定义的属性“包含”。当包含比较完成时,这发生在警卫中。我感觉我的代码确实有问题
  • 我认为它甚至不使用 getGroups 进行调用。因为错误显示得太快了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-13
  • 2019-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多