typescript 在装饰器中订阅RxJS Observable

g6ll5ycj  于 2023-10-22  发布在  TypeScript
关注(0)|答案(1)|浏览(130)

我试图在一个Angular应用程序中订阅一个TypeScript装饰器中的RxJS observable。
具体来说,我尝试创建一个@OnLogin()装饰器,当auth服务从login$$主体(公开为login$)发出时,它会导致服务中的一个方法执行。
授权服务:

// value doesn't matter, only that a login occurred
    private login$$ : BehaviorSubject<void>;

    get login$() : Observable<void> {
        return login$$.asObservable();
    }

下面是装饰器的定义(不工作):

export function OnLogin() {

    return function(target : any, propertyKey: string, descriptor: PropertyDescriptor) {

        const originalMethod = descriptor.value;

        descriptor.value = function(...args : any[]) {

            const authService : AuthService = AppModule.injector.get<AuthService>(AuthService);
            if (authService) {
                console.warn("Auth service found");
            } else {
                console.warn("No auth service found");
            }

            authService.login$
                .subscribe(() => {
                    originalMethod.apply(this, args);
                });

        }

        return descriptor;
    }
}

注入器作为AppModule的静态成员公开:
app.module.ts:

export class AppModule {
    static injector : Injector;

    constructor(injector : Injector) {
        AppModule.injector = injector;
    }
}

在一个使用装饰器的服务中,我希望调用看起来像这样:

@OnLogin()
doLogin() : void {
   // initialize items that need to do so on login
}

不幸的是,descriptor.value内部的装饰器函数根本没有执行,装饰函数也没有执行。我的一个想法是,我没有在对originalMethod.apply()的调用之前返回。但由于这只发生在$login发出时,这是正确的管理方法吗?

kiayqfof

kiayqfof1#

下面是代码的更新版本:
认证服务:

import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable({
  providedIn: 'root' // This is important to ensure there is a single instance of the service.
})
export class AuthService {
  private login$$: BehaviorSubject<void> = new BehaviorSubject<void>(null);

  get login$(): Observable<void> {
    return this.login$$.asObservable();
  }

  // You can trigger login events by calling next on login$$.
  login() {
    this.login$$.next();
  }
}

更新装饰:

import { Injectable, Injector } from '@angular/core';
import { AuthService } from './auth.service';
import { BehaviorSubject } from 'rxjs';

@Injectable()
export class OnLoginService {
  constructor(private authService: AuthService) {
    this.authService.login$.subscribe(() => {
      this.executeMethods();
    });
  }

  private methodsToExecute: BehaviorSubject<Function[]> = new BehaviorSubject([]);

  executeMethods() {
    this.methodsToExecute.value.forEach((method) => method());
  }

  registerMethod(method: Function) {
    const currentMethods = this.methodsToExecute.value;
    this.methodsToExecute.next([...currentMethods, method]);
  }
}

export function OnLogin() {
  return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
    // Assuming the class has a constructor
    const originalConstructor = target.constructor;

    // Inject the OnLoginService into the class
    constructor = function (...args: any[]) {
      const onLoginService = AppModule.injector.get(OnLoginService);
      onLoginService.registerMethod(() => {
        originalConstructor.apply(this, args);
      });
    };

    // Set the prototype
    constructor.prototype = originalConstructor.prototype;

    // Replace the class constructor
    return constructor;
  };
}

相关问题