【问题标题】:Observer only receives value from one next call观察者只从下一次调用中接收值
【发布时间】:2016-03-27 01:31:54
【问题描述】:

angular.io 示例的启发(父母和孩子通过服务进行通信),我实现了一个观察者/可观察模式来通知我的导航组件用户是否已通过身份验证。问题是导航组件只在用户注销时才会收到通知。

我的身份验证服务如下所示:

export class AuthenticationService {

  private isAuthenticatedSource = new Subject<boolean>();

  isAuthenticated$ = this.isAuthenticatedSource.asObservable();

  constructor(private http : AuthHttp) {}

  login(email: string, password: string) {
    ...
    this.isAuthenticatedSource.next(true);
    ...
  }

  logout() {
    ...
    this.isAuthenticatedSource.next(false);
    ...
  }

}

我已确保进行了两次调用(登录和注销)并且没有引发错误。我的导航组件如下所示:

export class NavigationComponent implements OnDestroy, OnInit {

  private subscription: Subscription;

  isAuthenticated: boolean;

  constructor(private authService: AuthenticationService,
              private router: Router) {
    this.isAuthenticated = authService.isAuthenticated();
  }

  logout(event) {
    event.preventDefault();
    this.authService.logout();
    this.router.navigate(["Authentication", "Login"]);
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }

  ngOnInit() {
    this.subscription = this.authService.isAuthenticated$.subscribe(
      value => console.log("updated to:", value)
    );
  }

}

登录时控制台应记录“更新为:true”,注销时应记录“更新为:false”。问题是它只在注销时显示一条消息。显然,观察者在登录时没有收到值(true)。希望您能帮助解释为什么会发生这种情况。

更新

登录调用现在包含在下面。当用户提交(登录)表单时,它会从我的LoginComponent 调用。 LoginComponent 看起来像:

export class LoginComponent {

  public email : string;
  public password : string;
  public errors : any;
  public next : any;

  constructor(private authService : AuthenticationService,
              private router : Router,
              private params : RouteParams) {
    // default to navigate to dashboard on successfull login
    let next = this.params.get("next") || "/Dashboard";
    this.next =  [next];
  }

  login(event) {
    event.preventDefault();
    this.authService.login(this.email, this.password)
                      .subscribe(
                        data => this.router.navigate(this.next),
                        errors => this.errors = errors);
  }

}

对应的模板有一个登录调用:&lt;form (submit)="login($event)"&gt;。 login 在应用程序的其他地方不会被调用。

【问题讨论】:

  • 您已经可以在构造函数中订阅,如果代码不依赖于正在更新的输入,则无需等待ngOnInit()。也许该事件在NavigationComponent 订阅之前已经发送。我认为您需要BehaviorSubject 才能在订阅后立即获得最后一个值。
  • 我没有在您的代码中看到对 login 的调用 - 您确定要在 订阅主题之后调用它吗? Subject 只会在订阅后向订阅者发送事件 - 你可能想要不同类型的 Subject,也许是 BehaviorSubject
  • 感谢您的反馈。尝试了 BehaviorSubject 并没有改变任何东西。我还将订阅调用移动到构造函数,但情况还是一样。 @tddmonkey 是的,我确定。当用户单击按钮时调用 login - 在 NavigationComponent 订阅主题很久之后。

标签: typescript angular rxjs


【解决方案1】:

我没有看到你在哪里调用登录。但是,我编写了一个示例,显示在订阅 UI 之前调用服务登录会重现您的观察结果,即 UI 未更新。请参阅 AppComponent 构造函数中的 authService.login() 调用对 UI 没有影响。这是因为订阅发生在 ngOnInit 的后面。希望这有用。

http://plnkr.co/edit/fteTLPCJUucCVKdVzJuP

export class AppComponent implements OnDestroy, OnInit { 

  @Output subscribe: string;
  private subscription: Subscription;
  private authService: AuthenticationService;

  constructor(private authService: AuthenticationService) {
    this.subscribe = 'not set';
    this.authService = authService;

    authService.login('john', 'password'); // has no affect on UI since login happens before subscribe in ngOnInit 
  }

  login() {
    this.authService.login('john', 'password');
  }

  logout() {
    this.authService.logout();
  }

  ngOnInit() {
    this.subscription = this.authService.isAuthenticated$.subscribe(
      //value => console.log("updated to:", value)
      value => this.subscribe = '' + value;
    );
  }

}

【讨论】:

  • 很好的例子。问题仍然存在。我已经更新了我的问题,还包括登录调用。如您所见,它发生在NavigationComponent 订阅之后。
【解决方案2】:

我不确定它为什么会起作用,但是将isAuthenticatedSource 设置为静态变量可以解决问题。将不得不进行更多研究以了解原因。感谢您的反馈。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多