Angular 2:未触发可观察/订阅

Angular 2: Observable / Subscription not triggering

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

我的问题:

我正在从组件 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 在 App 结构中处于较低层,因此 IboDetailsGeneralIBOsNavigationElementchild

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

NavigationModuleIBOsNavigationElement 的模块

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

控制台:

CALLING updateIBOsNavigation FUNCTION

updateIBOsNavigation "95"

CALLING updateIBOsNavigation FUNCTION AGAIN

updateIBOsNavigation "test"

这个控制台结果告诉我:

我的测试:

我真的很对不起我的'wall of text',但此时我有点绝望。

感谢任何帮助,谢谢!

更新一:

在第一个答案之后,我尝试了几种方法...

使用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:

我试过这种方法:

@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 的应用相同。

更新二:

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

使用 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 是一个 singleton:

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

导入时:

imports: [
        NavigationModule.forRoot()
       ]

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

实例

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

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

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

Behavior Subject

When an observer subscribes to a BehaviorSubject, it begins by emitting the item most recently emitted by the source Observable (or a seed/default value if none has yet been emitted) and then continues to emit any other items emitted later by the source Observable(s).

ReplaySubject

ReplaySubject emits to any observer all of the items that were emitted by the source Observable(s), regardless of when the observer subscribes.

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

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

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

A ReplaySubject 不需要默认值。

编辑

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

希望这对您有所帮助。

当我们在 'providers' 中包含服务时,它会被实例化,并且在其组件及其子组件之间维护此状态。

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

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

我也遇到了这个问题,并在此处的解决方案的帮助下解决了,

在我的例子中,我在父模块 "app.module" 和子模块中使用了相同的服务。我从子模块的提供商部分删除了服务。成功了。