【问题标题】:How to subscribe service in Angular如何在 Angular 中订阅服务
【发布时间】:2019-11-25 03:15:27
【问题描述】:

我有 3 个对象: - 第一个组件 - 连接服务 - 第二个组件

折叠/展开时的第一个组件应通过服务展开/折叠第二个组件。

在服务中,我有函数 toggle(),它应该只更改 boolean isOpen 的 bool 变量。在它旁边,我还有其他函数 getIsOpen(),返回类型为 Observable。代码如下所示:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/internal/Observable';
import { of } from 'rxjs/internal/observable/of';

@Injectable()
export class ConnectService {
  public isOpen = false;

  public toggle(): void {
    this.isOpen = !this.isOpen;
    console.log('Im inside toggle');
  }

  public getIsOpen(): Observable<boolean>{
    console.log('Im inside getIsOpen');
    return of(this.isOpen);
  }
}

在第二个组件中我尝试订阅:

public ngOnInit(): void {
  this.connectionService.getIsOpen().subscribe(x => this.isFirstComponentExpanded = x);
}

但只有在页面加载后,点击后,第二个组件没有折叠或展开。如何在没有事件发射器的情况下监听服务内部的每一个变化(我需要避免那里的任何事件发射器,只有可观察的、订阅和主题)。

【问题讨论】:

  • 查看stackblitz
  • 嗯,我有和你一样的实现,但......不工作。该死的......也许有一个问题,我认为有其他东西阻止了这个,但是如何:/
  • 从您的实现中创建一个堆栈闪电战。
  • 要添加的文件太多,但我有 1 对 1 并且在 stackblitz 上它工作正常,有我想要的 console.logs,内部应用程序无效。
  • 也许问题出在位置上?第一个组件与第二个组件是不同模块的一部分

标签: angular typescript service rxjs observable


【解决方案1】:

您可以使用BehaviorSubject()

@Injectable()
export class ConnectService {
  public isOpen = new BehaviorSubject(false);

  public toggle(): void {
    this.isOpen.next(!this.isOpen.getValue());
  }

  public getIsOpen(): Observable<boolean> {
    return this.isOpen.asObservable();
  }
}

【讨论】:

  • “Observable>”类型上不存在属性“asObservable”。在返回时(this.isOpen).asObservable();
  • @obar 抱歉,我忘了删除of(...)。我已经更新了答案。
  • 仍然无法进入 getIsOpen(),控制台日志仅在页面重新加载时记录
  • @obar getIsOpen() 只被调用一次
  • 是的,我不想在每次切换时多次调用它,而不仅仅是一次
【解决方案2】:

isOpenboolean。布尔值只是一个没有任何发布/订阅功能的原语。

您想要的是一个您可以实际订阅的Observable。我们将在这里使用BehaviorSubject,因为你可以给它一个初始值。

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/internal/Observable';
import { of } from 'rxjs/internal/observable/of';

@Injectable()
export class ConnectService {
  public isOpen$ = new BehaviorSubject(false);

  public toggle(): void {
    this.isOpen$.next(!this.isOpen$.getValue());
    console.log('Im inside toggle');
  }

  public getIsOpen(): Observable<boolean>{
    console.log('Im inside getIsOpen');
    return this.isOpen$;
  }
}

然后使用this.connectService.isOpen$.subscribe(isOpen =&gt; ...)订阅它。

【讨论】:

  • 我尝试像这样订阅上面的代码:this.connectService.isOpen$.subscribe(isOpen => this.firstComponentIsExpanded);并且在控制台中我只能让我进入切换(无法进入 getIsOpen())
  • 如果要使用getIsOpen,需要调用并订阅结果:this.connectService.getIsOpen().subscribe(isOpen =&gt; this.firstComponentIsExpanded);
  • 相同,只是让我进入切换。我在 getIsOpen 里面只在加载后出现一次,但我想每次都用切换出现。如果第一个组件切换服务,第二个组件必须每次都知道它
  • 那么请在 codepen 或类似网站上分享您的应用程序副本。
【解决方案3】:

of(this.isOpen) 只会发出一次值。您需要的是 BehaviorSubject 之类的东西,它始终会发出其最新值。

@Injectable()
export class ConnectService {

  public isOpen = new BehaviorSubject<boolean>(false);

  public toggle(): void {
    this.isOpen.next(!this.isOpen.value);
    console.log('Im inside toggle');
  }

}

然后在您的组件中,您可以直接订阅您的主题,无需创建额外的 Observable:

public ngOnInit(): void {
  this.connectionService.isOpen.subscribe(x => this.isFirstComponentExpanded = x);
}

【讨论】:

  • Value isFirstComponentExpanded 不会改变,我每次点击都会登录,但无法获取组件中服务内的 bool 值。
猜你喜欢
  • 2020-10-26
  • 1970-01-01
  • 2023-03-08
  • 1970-01-01
  • 2016-08-23
  • 1970-01-01
  • 1970-01-01
  • 2018-05-07
  • 2018-10-19
相关资源
最近更新 更多