Angular 2:Observable / Subscription不会触发

时间:2017-04-12 15:55:50

标签: angular angular2-observables

我在我的应用程序中多次这样做了。它很简单,它应该有用......但这次它没有。

我的问题:

我在组件A中调用服务中的方法,我的组件B已订阅但不做出反应也没有收到任何内容。 subscribe()未触发!

导航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
    ]
})

控制台:

  

调用updateIBOsNavigation FUNCTION

     

updateIBOsNavigation&#34; 95&#34;

     

再次调用updateIBOsNavigation功能

     

updateIBOsNavigation&#34; test&#34;

此控制台结果告诉我:

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

我的测试:

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

我真的很抱歉我的&#39;文字墙&#39; 但在这一点上我有点绝望。

任何帮助都是好的,谢谢!

更新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的一个实例。

3 个答案:

答案 0 :(得分:31)

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

有关http://reactivex.io/documentation/subject.html

中不同主题类型的更多信息
  

行为主题

     

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

     

<强> ReplaySubject

     

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

BehaviorSubject在设置时确实需要默认值。所以你需要创建一些有价值的东西:

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

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

ReplaySubject不需要默认值。

修改

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

希望这有帮助。

答案 1 :(得分:4)

当我们在&#39;提供商&#39;中包含服务时,它会被实例化,并且在其组件及其子组件之间维护此状态。

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

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

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

答案 2 :(得分:2)

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