【问题标题】:Angular 2: Observable / Subscription not triggeringAngular 2:可观察/订阅未触发
【发布时间】:2017-04-12 15:55:49
【问题描述】:

我已经在我的应用程序中多次这样做了。这很简单,它应该可以工作......但这次不行。

我的问题:

我正在从组件 A 调用服务中的方法,我的组件 B 已订阅但没有反应也没有收到任何东西。 subscribe() 没有触发!

navigation-elements.service.ts

@Injectable()
export class NavigationElementsService {
    updateIBOsNavigation$: Observable<any>;

    private updateIBOsNavigationSubject = new Subject<any>();

    constructor() {
        this.updateIBOsNavigation$ = this.updateIBOsNavigationSubject.asObservable();
    }

    updateIBOsNavigation(navigationData) {
        log.d('updateIBOsNavigation', JSON.stringify(navigationData));
        this.updateIBOsNavigationSubject.next(navigationData);
    }
}

IboDetailsGeneral 组件

export class IboDetailsGeneral implements OnInit, OnDestroy {
    id: string;
    private sub: any;

    constructor(private route: ActivatedRoute, private iboService: IBOsService, private navigationService: NavigationElementsService) {
        this.sub = this.route.params.subscribe(params => {
            this.id = params['id'];

            console.log('CALLING updateIBOsNavigation FUNCTION');
            this.navigationService.updateIBOsNavigation(this.id);
        });
    }

    ngOnInit() {
        console.log('CALLING updateIBOsNavigation FUNCTION AGAIN');
        this.navigationService.updateIBOsNavigation('test');
    }

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

该组件触发服务的方法:updateIBOsNavigation

IBOsNavigationElement 组件

export class IBOsNavigationElement implements OnInit {
    private id: string;

    constructor(private navigationService: NavigationElementsService) {
        this.navigationService.updateIBOsNavigation$.subscribe((navigationData) => {
                log.d('I received this Navigation Data:', JSON.stringify(navigationData));
                this.id = navigationData;
            }
        );
    }

    ngOnInit() {
    }
}

此组件已订阅,它应该列出并接收数据...

让我们整理一下 DI: 考虑到IboDetailsGeneral 位于应用程序结构的较低层,因此IboDetailsGeneralIBOsNavigationElement

这就是为什么我将NavigationElementsService 添加到IBOsNavigationElement 的模块中:

NavigationModuleIBOsNavigationElement的模块

@NgModule({
    imports: [
        // A lot of stuff
    ],
    declarations: [
        // A lot of stuff
        IBOsNavigationElement
    ],
    exports: [
        // A lot of stuff
    ],
    providers: [
        NavigationElementsService
    ]
})

控制台:

调用更新IBOsNavigation FUNCTION

更新IBOsNavigation "95"

再次调用 updateIBOsNavigation FUNCTION

更新IBOsNavigation“测试”

这个控制台结果告诉我:

  • 正在调用该方法,因此没有提供程序错误。 与服务人员沟通正常

我的测试:

  • 我已经尝试在IBOsNavigationElement中调用随机方法(监听器),与服务的通信很好。
  • NavigationElementsService 添加到providers 的唯一位置是在NavigationModule,所以只有一个服务实例对吗?然后,以下链接中解释的问题不会发生:Angular 2 observable subscription not triggering

我真的很抱歉我的“文字墙”,但此时我有点绝望。

感谢任何帮助,谢谢!

更新 1:

在第一个答案之后,我尝试了几件事......

使用ReplaySubject

@Injectable()
export class NavigationElementsService {
    public updateIBOsNavigation$ = new ReplaySubject();

    updateIBOsNavigation(navigationData) {
        log.d('updateIBOsNavigation', JSON.stringify(navigationData));
        this.updateIBOsNavigation$.next(navigationData);
    }
}

结果:调用updateIBOsNavigation()时,subscribe()仍然没有触发。

使用BehaviorSubject:

@Injectable()
export class NavigationElementsService {
    updateIBOsNavigationSubject = new BehaviorSubject<any>('');
     updateIBOsNavigation$ = this.updateIBOsNavigationSubject.asObservable();

    updateIBOsNavigation(navigationData) {
        log.d('updateIBOsNavigation', JSON.stringify(navigationData));
        this.updateIBOsNavigationSubject.next(navigationData);
    }
}

结果:初始化时进入subscribe(),但是当我调用updateIBOsNavigation()时,subscribe()仍然没有触发。

使用BehaviorSubject v2:

我试过这种方法:behaviourSubject in angular2 , how it works and how to use it

@Injectable()
export class NavigationElementsService {
    public updateIBOsNavigation$: Subject<string> = new BehaviorSubject<string>(null);

    updateIBOsNavigation(navigationData) {
        log.d('updateIBOsNavigation', JSON.stringify(navigationData));
        this.updateIBOsNavigation$.next(navigationData);
    }
}

结果:与之前的BehaviorSubject申请相同。

更新 2:

在整个网络上进行研究后,更多的绝望尝试示例......

使用BehaviorSubject v3:

@Injectable()
export class NavigationElementsService {
    updateIBOsNavigation$: Observable<any>;
    updateIBOsNavigationSubject = <BehaviorSubject<any>> new BehaviorSubject([]);

    constructor() {
        this.updateIBOsNavigation$ = this.updateIBOsNavigationSubject.asObservable();
    }

    updateIBOsNavigation(navigationData) {
        log.d('updateIBOsNavigation()', JSON.stringify(navigationData));
        this.updateIBOsNavigationSubject.next(navigationData);
    }
}

结果:与之前的BehaviorSubject 尝试相同...绝望正在上升...

更新 3:

以防万一,我想确保NavigationElementsService 是一个单例

export class NavigationModule {
    static forRoot() {
        return {
            ngModule: NavigationModule,
            providers: [NavigationElementsService]
        };
    }
}

导入时:

imports: [
        NavigationModule.forRoot()
       ]

结果:同样的问题,subscribe() 没有触发,但至少我知道有一个 NavigationElementsService 的实例。

【问题讨论】:

  • 我正在为我绝望的尝试添加更新...请结束我的折磨! xD
  • 嗨,你现在解决这个问题了吗?
  • @BonesandTeeth 是的!谢谢! :D
  • 你能告诉我你做了什么让它工作吗?我也面临同样的问题......
  • @BonesandTeeth 当然,只需阅读答案和随后的所有 cmets。在我的最后一条评论中,我解释了我是如何解决我的问题的。希望你也解决!干杯!

标签: angular angular2-observables


【解决方案1】:

我认为问题在于您的Subject 类型使用Subject,在事件触发后订阅的任何组件都不会收到值。要向迟到的订阅者重播之前的值,请使用 BehaviorSubjectReplaySubject 而不是 Subject

更多关于不同主题类型的信息来自http://reactivex.io/documentation/subject.html

行为主体

当观察者订阅 BehaviorSubject 时,它首先发出源 Observable 最近发出的项目(如果还没有发出种子,则为种子/默认值),然后继续发出稍后由源 Observable 发出的任何其他项目源 Observable。

重播主题

无论观察者何时订阅,ReplaySubject 都会向任何观察者发出源 Observable 发出的所有项目。

BehaviorSubject 在设置时确实需要默认值。所以你需要用某种价值来创建它:

updateIBOsNavigationSubject = new BehaviorSubject<any>('');
updateIBOsNavigation$ = this.updateIBOsNavigationSubject.asObservable();

updateIBOsNavigation(navigationData) {
    log.d('updateIBOsNavigation', JSON.stringify(navigationData));
    this.updateIBOsNavigationSubject.next(navigationData);
}

ReplaySubject 不需要默认值。

编辑

使用共享服务时,确保仅在根模块提供服务也很重要。如果提供了多个位置,则组件可能不会获得相同的实例。即使服务是在根级别提供的,如果根级别和您的组件之间的模块提供服务,新的实例将被发送到依赖注入树的该分支。

希望这会有所帮助。

【讨论】:

  • @TylerJennings 再次感谢!但是,仍然只工作 1 次,而不是当我打电话给updateIBOsNavigation()
  • 有趣。听起来一切都应该正常工作。你说subscribe() 只能用一次就不能再用了?
  • 包含此服务的模块是否仅在第一个根模块中提供?根模块和这些组件所在的模块之间的另一个模块是否有可能创建一个新的服务实例?我在回答中提供的示例,我在几个地方使用完全相同的语法没有问题。
  • @TylerJennings 难以置信的时机!我正要自己发布 the 答案。我刚刚让它工作了!确切地说,这是因为服务包含在AppModule 和最终组件之间的@Module 中。所以,Subject 的类型无关,它是服务的包含:必须在根模块中 = AppModule。如果您想将此添加到您的问题中,我可以将其作为正确答案,否则我会发布带有更新代码的答案。无论如何,你的回答显然是我的 +1,而且我在过去 24 小时内研究了很多关于主题类型的知识。谢谢!
  • “编辑”部分应该在顶部,因为这才是真正有帮助的 :)
【解决方案2】:

当我们在“提供者”中包含服务时,它会被实例化,并且在其组件及其子组件之间保持此状态。

而且,如果我们将服务包含在两个组件提供程序数组中,那么它就不再是单例了。状态将是独立的,不会在它们之间共享。

因此,仅在父组件或根组件中包含您的服务。

我也遇到了这个问题,并在此解决方案的帮助下解决了,https://stackoverflow.com/a/38034298/5730167

【讨论】:

    【解决方案3】:

    就我而言,我在父模块“app.module”和子模块中使用相同的服务。我从子模块的提供者部分删除了服务。成功了。

    【讨论】:

      猜你喜欢
      • 2017-07-23
      • 1970-01-01
      • 1970-01-01
      • 2016-09-19
      • 1970-01-01
      • 2016-10-28
      • 1970-01-01
      • 2016-06-10
      • 1970-01-01
      相关资源
      最近更新 更多