rxjs Observable 与预解析数据混合

rxjs Observable mixed with pre-resolved data

我有两个可观察的数据流。一取账号,一取权限。

我需要做的是检查当前用户是否具有管理员角色,或者具有外部角色并且当前帐户没有设置标志。但是我不知道如何使用 rxjs 做到这一点。

这是一个精简的测试用例,用于展示我正在尝试做的事情,但是因为运行时所有数据都不存在(帐户为空,或者权限尚未加载) yet), 它出错了。

我怎样才能使这个工作?

我正在使用 rxjs6。

export class ViewComponent implements OnInit {
    private account: AdminUser;
    private permissions: Permissions;

    constructor(private _service: AdminUserService,
                private _permissions: PermissionsService,
                private _activatedRoute: ActivatedRoute) {
    }

    canEdit(): boolean {
        let isAdmin = this.permissions.hasRole('Admin');
        return isAdmin || (this._permissions.hasRole('External') && !this.account.isActiveDirectory);
    }

    ngOnInit() {
        this._permissions
            .getPermissions()
            .subscribe(p => this.permissions = p);

        this._activatedRoute.params.subscribe(
            params => {
                    this._service.get(params.id)
                        .pipe(map(account => this.account = account))
                        .subscribe();
            });
    }
}

我只是猜测你的目标可能是什么。但是检查你的代码我认为你正在寻找这样的解决方案。

export class ViewComponent implements OnInit, OnDestroy {
    // provide this information as boolean
    canEdit = false;

    private account: AdminUser;
    private permissions: Permissions;

    // allways collect at start and remove all subscriptions when leaving the component
    private subscription: Subscription = new Subscription();


    constructor(private _service: AdminUserService,
                private _permissions: PermissionsService,
                private _activatedRoute: ActivatedRoute) { }

   

    ngOnInit(): void {
                  
        this.subscription.add(  
            this._permissions
                .getPermissions()
                .subscribe(permissions => {
                    this.permissions = permissions;

                    this.checkPermissions();
            })
        );

        this.subscription.add(
            this._activatedRoute.params.subscribe(
                params => {
                    this._service.get(params.id).subscribe(account =>
                    this.account = account);
                        
                    this.checkPermissions();
            })
        );
    }

    ngOnDestroy(): void {
        // unsubscribe all subscriptions
        this.subscription.unsubscribe();
    }


    checkPermissions(): void {
        if (this.permissions && this.account) {
            this.canEdit = this.permissions.hasRole('Admin') ||
            (this._permissions.hasRole('External') && !this.account.isActiveDirectory);
        }
    }

在您的 HTML 中,我猜您想要(取消)激活一个按钮左右。那就这样吧

<button  [disabled]="!canEdit">Edit something</button>

您可以将数据保留为可观察对象,而无需订阅您的组件。 Rxjs 有许多操作符和静态函数来塑造、过滤和转换它们以满足您的需要。

而不是将account定义为AdminUser,将permissions定义为Permissions;让我们将它们定义为 Observable<AdminUser>Observable<Permissions>.

然后我们可以使用 combineLatest 创建一个发出 canEdit 值的单个 observable。

export class ViewComponent {
  private id$ = this._activatedRoute.params.pipe(map(params => params.id));
  private account$ = this.id$.pipe(switchMap(id => this._service.get(id)));
  private permissions$ = this._permissions.getPermissions();
  
  public canEdit$ = combineLatest([this.account$, this.permissions$]).pipe(
    map(([account, permissions]) => 
      permissions.hasRole("Admin") ||
      (permissions.hasRole("External") && !account.isActiveDirectory)
    )
  );

  constructor(
    private _service: AdminUserService,
    private _permissions: PermissionsService,
    private _activatedRoute: ActivatedRoute
  ) { }
}

如果您不熟悉 switchMap,它基本上会为您订阅一个“内部可观察对象”并发出结果。在这种情况下,获取 id 并调用 service.get(id).


您似乎还想在模板中使用帐户信息以及 canEdit 值。我们可以发出一个对象,其中包含我们视图所需的所有数据(视图模型):

,而不是发出单个 boolean
export class ViewComponent {
  private id$ = this._activatedRoute.params.pipe(map(params => params.id));
  private account$ = this.id$.pipe(switchMap(id => this._service.get(id)));
  private permissions$ = this._permissions.getPermissions();
  
  public vm$ = combineLatest([this.account$, this.permissions$]).pipe(
    map(([account, permissions]) => {
      const canEdit = permissions.hasRole("Admin") || (permissions.hasRole("External") && !account.isActiveDirectory)

      return { account, canEdit };
    })
  );

  constructor(
    private _service: AdminUserService,
    private _permissions: PermissionsService,
    private _activatedRoute: ActivatedRoute
  ) { }
}

您现在可以在模板中使用单个 async 管道来为您处理订阅:

<ng-container *ngIf="vm$ | async as vm">
  <h1>{{ vm.account.name }}</h1>
  ...
  <button *ngIf="vm.canEdit">Edit</button>
</ng-container>