Angular 2:Observable/Subscription不会触发

SrA*_*Axi 17 angular2-observables angular

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

我的问题:

我在组件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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

该组件触发服务的方法: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() {
    }
}
Run Code Online (Sandbox Code Playgroud)

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

让我们理清DI:考虑到IboDetailsGeneral应用程序结构中的较低层,所以IboDetailsGeneral孩子IBOsNavigationElement.

这就是为什么我添加NavigationElementsServiceIBOsNavigationElement的模块:

NavigationModuleIBOsNavigationElement模块

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

安慰:

调用updateIBOsNavigation功能

updateIBOsNavigation"95"

再次呼叫updateIBOsNavigation功能

updateIBOsNavigation"test"

这个控制台结果告诉我:

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

我的测试:

  • 我试过在IBOsNavigationElement (监听器)中调用一个随机方法,并且与服务的通信很好.
  • 其中唯一的地方NavigationElementsService加入到providersNavigationModule,所以只有一个的服务正确的实例?然后,以下链接中解释的问题不会发生:Angular 2可观察订阅不会触发

我真的很抱歉我的"文本墙",但在这一点上,我有点绝望.

任何帮助都是有意义的,谢谢!

更新1:

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

使用ReplaySubject:

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

    updateIBOsNavigation(navigationData) {
        log.d('updateIBOsNavigation', JSON.stringify(navigationData));
        this.updateIBOsNavigation$.next(navigationData);
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:通话时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);
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:它进入subscribe()初始化但是当我打电话时updateIBOsNavigation(),subscribe()仍然没有触发.

使用BehaviorSubjectv2:

我尝试了这种方法:behaviourSubject in angular2,它是如何工作的以及如何使用它

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

    updateIBOsNavigation(navigationData) {
        log.d('updateIBOsNavigation', JSON.stringify(navigationData));
        this.updateIBOsNavigation$.next(navigationData);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

更新2:

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

使用BehaviorSubjectv3:

@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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

更新3:

为了以防万一,我想确保它NavigationElementsService是一个单身人士:

export class NavigationModule {
    static forRoot() {
        return {
            ngModule: NavigationModule,
            providers: [NavigationElementsService]
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

并在导入时:

imports: [
        NavigationModule.forRoot()
       ]
Run Code Online (Sandbox Code Playgroud)

结果:一如既往的问题,subscribe()没有触发,但至少我知道有一个实例NavigationElementsService.

Tyl*_*ngs 35

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

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

行为主体

当观察者订阅BehaviorSubject时,它首先发出源Observable最近发出的项(或者如果尚未发出种子/默认值),然后继续发出源Observable稍后发出的任何其他项( S).

ReplaySubject

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

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

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

updateIBOsNavigation(navigationData) {
    log.d('updateIBOsNavigation', JSON.stringify(navigationData));
    this.updateIBOsNavigationSubject.next(navigationData);
}
Run Code Online (Sandbox Code Playgroud)

A ReplaySubject不需要默认值.

编辑

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

希望这可以帮助.

  • 包含此服务的模块是否仅在第一个根模块中提供?根模块和这些组件所在的模块之间的另一个模块是否有可能创建服务的新实例?我在答案中提供的示例,我在几个地方使用完全相同的语法没有问题。 (2认同)
  • @TylerJennings令人难以置信的时机!我本人即将发布**答案.我刚刚开始工作了!确切地说,这是因为服务被包含在`AppModule`和最终组件之间的`@ Module`中.所以,`Subject`的类型无关,它是包含服务:**必须在root模块=`AppModule`**.如果你想将它添加到你的问题我可以把它作为正确的答案,如果不是,我发布一个更新代码的答案.无论如何,你回答得很清楚我的+1并且我在过去的24小时里学到了很多关于主题类型的研究.谢谢! (2认同)

小智 5

当我们在“提供者”中包含服务时,将对其进行实例化,并在其组件及其子组件之间维持此状态。

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

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

我也遇到了这个问题,并在这里/sf/answers/2662400891/的帮助下解决了该问题。