2

I'm trying to write a basic angular 2 app, which uses the new version of RxJS -> "rxjs": "5.0.0-beta.6".

I have followed the instructions from the cookbook, trying to make a notifications service, which any part of my app could call to show a message.

The issue I'm having is that when I call .next() to add the next notification, this is not picked up by the subscription. The this.displayMessage(notification); line doesn't run after a call to newNotification. I added the BehaviourSubject type to my code (as opposed to the Subject used in the tutorial) and found the initial value was picked up by the subscription - the this.displayMessage(notification); was called successfully on initialization. This makes me think it is something to do with how/where I am calling .next() in the NotificationService class.

Here are the relevant classes:

NotificationService:

import { Injectable } from '@angular/core';
import { BehaviorSubject }    from 'rxjs/BehaviorSubject';
import { Notification } from '../notification/notification';

@Injectable()
export class NotificationService {
  // Observable string sources
  private notificationSource = new BehaviorSubject<Notification>(new Notification({message:"test", priority:-1}));
  notifications$ = this.notificationSource.asObservable();

  newNotification(message: string, priority: number) {
    this.notificationSource.next(new Notification({ message, priority }));
  }

}

MessageComponent:

import { Component, OnDestroy, OnInit } from '@angular/core';

import { Notification } from '../notification/notification';
import { NotificationService } from '../notification.service/notification.service';
import {MdIcon, MdIconRegistry} from '@angular2-material/icon';
import { Subscription }   from 'rxjs/Subscription';

@Component({
  selector: 'message-container',
  styleUrls: ['./app/message/message.component.css'],
  templateUrl: './app/message/message.component.html',
  directives: [MdIcon],
  providers: [NotificationService, MdIconRegistry]

})
export class MessageComponent implements OnDestroy, OnInit {
  notification: Notification;
  subscription: Subscription;
  constructor(
    private notificationService: NotificationService) {
    this.notificationService = notificationService;
  }
  ngOnInit() {
    this.subscription = this.notificationService.notifications$.subscribe(
      notification => {
        this.displayMessage(notification);
      }, err => console.log(err), () => console.log("completed: "));
  }

  displayMessage(notification: Notification) {
    this.notification = notification;
    window.setTimeout(() => { this.notification = null }, 3000);
  }
  ngOnDestroy() {
    // prevent memory leak when component destroyed
    this.subscription.unsubscribe();
  }
}

If anyone has any ideas about other things to try that would be great. Many thanks

Edit: full repo here: https://github.com/sandwichsudo/sentry-material/tree/notifications/src/app

Gilly Ames
  • 361
  • 4
  • 12

1 Answers1

2

GitHub doesn't find NotificationService in your repository.

I assume that you are providing NotificationService more than once and therefore different instances are created with the result that you are subscribing to one instance and sending on another instance.

Ensure you have NotificationService either only in bootstrap(AppComponent, [NotificationService, ...]) or only in providers: [NotificationService] in your AppComponent. Remove it from providers: [...] from all other components and directives.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • Thanks very much for the reply - I have updated the repo url for the correct branch https://github.com/sandwichsudo/sentry-material/tree/notifications/src/app. I'll check for what you suggest, though I'm confident I don't bootstrap it in anywhere, but the symptoms sounds right. – Gilly Ames Jun 15 '16 at 15:41
  • GitHub just doesn't find anything. Maybe it first needs to index your repository. Did you check if you provide the service more than once? – Günter Zöchbauer Jun 15 '16 at 15:43
  • I've had a look and I only use the NotificationService in providers. Here is the file with bootstrapping: https://github.com/sandwichsudo/sentry-material/blob/notifications/src/main.ts and notification service doesn't appear. I'm not sure why the search doesn't find it, it's for sure in this file: https://github.com/sandwichsudo/sentry-material/blob/notifications/src/app/notification.service/notification.service.ts – Gilly Ames Jun 15 '16 at 15:49
  • Ahh sorry are you saying it should not be 'provided' more than once ever? – Gilly Ames Jun 15 '16 at 15:51
  • 1
    I'm currently adding it as a provider to more than one component - I'll bring to to the top level and give that a go tonight. Makes a lot of sense thank you. – Gilly Ames Jun 15 '16 at 15:58
  • Angular DI maintains a single instance per provider. If you provide it more than once you get more than one instance. If you provide it once at the top (`bootstrap()` or root component) you get a single instance for your whole application (pretty close to a singleton). There are situations where you don't want to share with your whole application but only with a component and its children. Then you provide it on this component. – Günter Zöchbauer Jun 15 '16 at 15:59
  • There might be overlaps that you want an instance for the whole application but a subtree should have it's own instance then you provide it twice. DI looks from the component where the dependency is requested upwards to the first provider it finds and then returns the instance from there. – Günter Zöchbauer Jun 15 '16 at 15:59