angular - 在函数上调用订阅时无法读取未定义的属性“订阅”
问题描述
我正在使用 jwt 令牌,我需要知道用户的角色来决定客户端允许哪些路由以及我在导航栏中显示哪个菜单。
所有这些都保存在一个服务中,该服务应该告诉 app-routing 模块用户是否被允许访问此路由,以及导航栏是否应该显示菜单。
这是有效的现有解决方案:
安全服务.ts
import { ApplicationRef, EventEmitter, Injectable, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from "rxjs";
import { ActivatedRouteSnapshot, RouterStateSnapshot } from "@angular/router";
import { LoggingUtil } from "../utils/logging.util";
import { ServerUtil } from "../utils/server.util";
import { UserRoleModel } from "../model/models-generated";
import { Log } from "@angular/core/testing/src/logger";
@Injectable({
providedIn: 'root'
})
export class SecurityService {
constructor(private client: HttpClient) {}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
if (next.data.permission.includes(SecurityService.AVA_PERMISSION)) {
this.getUserRoles().subscribe((result) => {
return of(result.hasAvaRole);
});
} else if (next.data.permission.includes(SecurityService.ADMIN_PERMISSION)) {
this.getUserRoles().subscribe((result) => {
return of(result.hasAdminRole);
});
} else if (next.data.permission.includes(SecurityService.USER_PERMISSION)) {
this.getUserRoles().subscribe((result) => {
return of(result.hasUserRole);
});
}
return of(false);
}
public getUserRoles(): Observable<UserRoleModel> {
let serverUrl = ServerUtil.GetRestApiURL() + '/role';
return this.client.get<UserRoleModel>(serverUrl);
}
navbar.component.ts
import {Component, OnInit} from '@angular/core';
import {SecurityService} from "../../services/security.service";
import {Observable} from "rxjs";
@Component({
selector: 'app-navbar',
templateUrl: "./navbar.component.html",
styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
isAdmin: boolean;
constructor(private securityService: SecurityService) {}
ngOnInit() {
this.securityService.getUserRoles().subscribe(value => {
this.isAdmin = value.hasAdminRole;
})
}
}
这个版本的问题是canActivate()将在每次路由更改时调用,因此也会调用getUserRoles()。
我的目标是做到这一点,你既可以用旧方式做,也可以存储价值。切换是在弹簧轮廓的帮助下完成的,因此我将代码更改如下:
安全服务.ts
export class SecurityService {
hasAvaRole = false;
hasAdminRole = false;
hasUserRole = false;
profiles: string[] = [];
profileLoaded = false;
// previously getUserRoles
loadRoles(): Observable<UserRoleModel> {
let serverUrl = ServerUtil.GetRestApiURL() + '/' + this.ACTION_PATH;
LoggingUtil.debug("posting to remote server : " + serverUrl);
return this.client.get<UserRoleModel>(serverUrl);
}
loadProfiles(): Observable<string[]> {
let serverUrl = ServerUtil.GetRestApiURL() + '/' + this.PROFILE_PATH;
LoggingUtil.debug("calling remote server : " + serverUrl);
LoggingUtil.debug('client info :');
console.log(this.client);
return this.client.post<string[]>(serverUrl, null);
}
private getUserRolesSync(): UserRoleModel {
return {'hasAvaRole': this.hasAvaRole, 'hasAdminRole': this.hasAdminRole, 'hasUserRole': this.hasUserRole}
}
getUserRoles(): Observable<UserRoleModel> {
// if roles aren't in memory we load them
if (!this.profileLoaded) {
this.loadProfiles().subscribe((profiles: string[]) => {
this.profiles = profiles;
this.profileLoaded = true;
if (this.profiles.includes('saving-role')) {
this.loadRoles().subscribe(result => {
this.hasAvaRole = result.hasAvaRole;
this.hasAdminRole = result.hasAdminRole;
this.hasUserRole = result.hasUserRole;
return of(this.getUserRolesSync());
});
} else {
return this.loadRoles();
}
});
} else {
if (this.profiles.includes('saving-role')) {
return of(this.getUserRolesSync());
} else {
return this.loadRoles();
}
}
起初我以为 httpClient 没有被注入,但通过打印它我发现事实并非如此。弹簧型材也已正确加载。
我现在在订阅函数的行的 navbar.component.ts 中收到错误“无法读取未定义的属性‘订阅’”
解决方案
问题在这里getUserRoles
。如果用户进入第一个if
条件,则控件将进入subscribe
块内。但是你没有从那里返回任何东西。所以你必须return
从那里开始。而不是subscribe
ing,您必须将上下文切换到内部 Observable:pipe
switchMap
getUserRoles(): Observable < UserRoleModel > {
// if roles aren't in memory we load them
if (!this.profileLoaded) {
return this.loadProfiles().pipe(
switchMap(profiles: string[]) => {
this.profiles = profiles;
this.profileLoaded = true;
if (this.profiles.includes('saving-role')) {
this.loadRoles().pipe(
switchMap(result => {
this.hasAvaRole = result.hasAvaRole;
this.hasAdminRole = result.hasAdminRole;
this.hasUserRole = result.hasUserRole;
return of(this.getUserRolesSync());
})
);
} else {
return this.loadRoles();
}
})
);
}
else {
if (this.profiles.includes('saving-role')) {
return of(this.getUserRolesSync());
} else {
return this.loadRoles();
}
}
}
推荐阅读
- python - 继承与python中的扩展
- reactjs - 如何设置我的 webpack 来配置 sass-loader?
- c# - 第二次窗口应用程序运行问题?
- java - 向 executorservice 添加更多线程只会使其变慢
- hibernate - JPA @JoinFormula 与 BindParameter
- c - 测量存储延迟时的 C 微基准测试“错误”
- python - Django 测试不起作用,但视图起作用
- .net-core - 在 Azure Devops 中发布 .net core 3.1 api 发布另一个 web 项目
- javascript - 将 HTML 转换为我有输入字段的 Word DOC
- angular - Spring请求参数没有从角度获取数据