如何在订阅中等待数据

huangapple go评论48阅读模式
英文:

How to wait for data in subscribe

问题

在Angular中,我在使用这个服务时遇到了问题。当我想要从后端通过令牌获取用户的角色,并在hasRole()方法中检查这个角色时,我得到了未定义的数据。这是因为数据角色尚不存在。当我第二次运行这个服务时,它就正常工作了。如何获取数据并告诉服务等待它们。

export class JwtService {

  roles: string[] = [];
  
  constructor(
    private http: HttpClient,
    private loginService: LoginService
  ) { }

  hasRole(rolea: string): boolean {
    if (this.roles.length === 0) {
      this.saveRole();
    }
    return this.roles.includes(rolea);
  }

  saveRole() {
    this.http.get<string[]>(`/api/getRole/${this.getToken()}`).subscribe(role => this.roles = role);
  }
}
英文:

I have a problem with this service in angular. When I want to get users' roles by token from backend and in method hasrole() check this role - I get undefined data. Because data roles don't exist yet. When I run this service a second time it works great. How to get data and tell service to wait for them.

export class JwtService {

  roles: string[] = [];
  
  constructor(
    private http: HttpClient,
    private loginService: LoginService
  ) { }

  hasRole(rolea: string): boolean {
    if (this.roles.length  === 0) {
      this.saveRole();
    }
    return this.roles.includes(rolea);
  }

  saveRole() {
    this.http.get&lt;string[]&gt;(`/api/getRole/${this.getToken()}`).subscribe(role =&gt; this.roles = role);
  }
}

答案1

得分: 1

更新 将"switchMap"替换为"map"
记住:"您的服务返回Observables,您在组件中订阅。"

您可以重构您的服务如下:

<strike>

// 见到返回一个 observable
// 您使用了rxjs运算符"of"
hasRole(rolea: string): Observable<boolean> {
    if (this.roles.length === 0) {
        return this.saveRole().pipe(
            // 使用 switchMap,返回不是返回角色的 observable
            // 而是一个 observable "true|false"
            switchMap((roles: string[]) => {
                this.roles = roles; // <-- 存储角色
                return of(this.roles.includes(roles));
            })
        );
    } else {
        return of(this.roles.includes(roles));
    }
}

</strike>

// 见到返回一个 observable
// 您使用了rxjs运算符"of"
hasRole(rolea: string): Observable<boolean> {
    if (this.roles.length === 0) {
        return this.saveRole().pipe(
            map((roles: string[]) => {
                this.roles = roles; // <-- 存储角色
                return this.roles.includes(roles);
            })
        );
    } else {
        return of(this.roles.includes(roles));
    }
}


// 我想象您的函数getToken()也返回一个 Observable
saveRole(): Observable<string[]> {
    return this.getToken().pipe(
        switchMap((token: string) =>
            this.http.get<string[]>(`/api/getRole/${this.getToken()}`)
        )
    );
}

所以您可以使用类似以下的方式

<div *ngIf="myService.hasRole('admin') | async">
    I am admin
</div>
英文:

Update replace the "switchMap" by "map"
Remember: "Your services return Observables, you subscribe in components."

You can re-structure your service in the way
<strike>

//see that return an observable
//You use rxjs operator &quot;of&quot;
hasRole(rolea: string): Observable&lt;boolean&gt; {
    if (this.roles.length  === 0) {
      return this.saveRole().pipe(
        //use switchMap, to return not the observable that return the roles
        //else an observable &quot;true|false&quot;
        switchMap((roles:string[])=&gt;{
           this.roles=roles; //&lt;--store the roles
           return of(this.roles.includes(roles))
        })
      )
    }
    else
      return of(this.roles.includes(roles))
  }

</strike>

//see that return an observable
//You use rxjs operator &quot;of&quot;
hasRole(rolea: string): Observable&lt;boolean&gt; {
    if (this.roles.length  === 0) {
      return this.saveRole().pipe(
        map((roles:string[])=&gt;{
           this.roles=roles; //&lt;--store the roles
           return this.roles.includes(roles)
        })
      )
    }
    else
      return of(this.roles.includes(roles))
  }


  //I imagine that your function getToken() also return an Observable
  saveRole():Observable&lt;string[]&gt; {
    return this.getToken().pipe(
        switchMap((token:string)=&gt;
                    this.http.get&lt;string[]&gt;(`/api/getRole/${this.getToken()}`));
  }

So you can use some like

  &lt;div *ngIf=&quot;myService.hasRole(&#39;admin&#39;)|async&quot;&gt;
      I am admin
  &lt;/div&gt;

答案2

得分: 1

hasRole 应该返回一个类似这样的 Observable

hasRole(role: string): Observable<boolean> {
    if (this.roles.length === 0) {
        return this.saveRole().pipe(
            map(roles => roles.includes(role))
        );
    } else {
        return of(this.roles.includes(role));
    }
}

然后在你的组件中订阅它:

JwtService.hasRole('someRole').subscribe(hasRole => this.hsRole = hasRole);

tapmap 都是rxjs操作符,tap 用于副作用,而 map 用于将值映射为其他值 - 在你的情况下,将其映射为布尔值。

of 是一个rxjs函数,用于实例化一个Observable并提供你提供的值。在这种情况下,我们使用它在不需要http请求的情况下返回一个Observable,因为数据已经被获取。

英文:

The hasRole should return an Observable like this:

hasRole(role: string): Observable&lt;boolean&gt;{
    if (this.roles.length  === 0) {
      return this.saveRole().pipe(
                 map(roles =&gt; roles.includes(rolea))
             );
    }else{
      return of(this.roles.includes(rolea));
    }
    

saveRole(): Observable&lt;string[]&gt; {
    return this.http.get&lt;string[]&gt; 
           (`/api/getRole/${this.getToken()}`).pipe(
             tap(roles =&gt; this.roles = roles)
          );
  }

And then subscribe to it in your component:

JwtService.hasRole(&#39;someRole&#39;).subscribe(hasRole =&gt; this.hsRole = hasRole)

tap & map are both rxjs operators, tap is for side effects and map just maps the value into something else - in your case into a boolean.

of is a rxjs function that instantiate an Observable on go with the value you supply. In this case, we used it to return an Observable when no http request is needded since the data is already fetched.

huangapple
  • 本文由 发表于 2023年7月10日 15:36:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76651611.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定