微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

rxjs Observable 与预先解析的数据混合

如何解决rxjs Observable 与预先解析的数据混合

我有两个可观察的数据流。一个检索帐户,一个获得权限。

我需要做的是检查当前用户是否具有admin角色,或者是否具有external角色并且当前帐户没有设置标志。但是如何使用 rxjs 做到这一点让我很困惑。

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

我怎样才能做到这一点?

我使用的是 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();
            });
    }
}

解决方法

您可以将数据保留为可观察对象,而无需订阅您的组件。 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,它基本上会为您订阅一个“内部 observable”并发出结果。在本例中,使用 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$,permissions]) => {
      const canEdit = permissions.hasRole("Admin") || (permissions.hasRole("External") && !account.isActiveDirectory)

      return { account,canEdit };
    })
  );

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

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

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

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

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 _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>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。