1

I'm using the BehaviorSubject class to update the number of notifications in my global. I have 2 components : the component notification shows a list of notifications and you can set these notifications as read. The header component shows the number of notifications who are not read to let the user know that he missed something on the website. Since there are 2 different components, I'm using a service to communicate through them.

Here some snippet :

notification.service.ts

export class NotificationService {
     public notification: BehaviorSubject<Object> = new BehaviorSubject<Object>({});
     public nbNotificationsChange: BehaviorSubject<number>;

constructor(){
     this.nbNotificationsChange = new BehaviorSubject<number>(0);
}

updateNbNotification(value) {
    this.nbNotificationsChange.next(value);
    this.nbNotificationsChange.subscribe(x => console.log(x));
}

getNbNotification(){
    return this.nbNotificationsChange.getValue();
} }

header.component.ts

export class HeaderComponent implements OnInit, DoCheck {
    public notifications: Notification[] = [];
    public nbNotifications: number = 0;


    constructor (public notificationService: NotificationService){
    this.notificationService.nbNotificationsChange.subscribe(value => {
            this.nbNotifications = value;
        });
    }
ngOnInit() {
    this.getNotificationsNotRead();
    this.notificationService.nbNotificationsChange.subscribe(value => {
        this.nbNotifications = value;
    });
}

ngDoCheck(){
    this.nbNotifications = this.notificationService.getNbNotification()
    //console.log("test");
}
getNotificationsNotRead(){
    aNotRelevantFunctionToRetreiveNotification.subscribe(
            this.notifications = //Receive an array of Notifications here with some code
            this.notifications = this.notifications.filter((notif : Notification) => notif.seen == false); // Check if a notification is read or not
            this.notificationService.updateNbNotification(this.notifications.length);
            console.log(this.notifications.length);
    );
}

get nbNotif(): number {
    return this.notificationService.getNbNotification();
} }

notification.component.ts

export class NotificationsComponent implements OnInit {

public notifications: Notification[];

constructor(public notificationService: NotificationService) {}

ngOnInit() {
    this.getAllNotifications();
}

public getAllNotifications() {
    //Receive an array of notifications to display them, passsing this code. We're in the subscribe
    var nbNotifNotRead = this.notifications.filter((notif : Notification) => notif.seen == false).length;
    this.notificationService.updateNbNotification(nbNotifNotRead); //This value is properly set
}
}

Problem is, even if the value is set on notification.component.ts side, the value retreived in the header.component.ts is not the good and is the initial one, witch is not what I want of course.

Does anyone have an idea ? Been struggling on this for too much time now


Update

Here is the html part, wich is very simple :

<span class="SomeCSSClasses" *ngIf="nbNotifications > 0">{{nbNotifications}}</span>

Update 2

The module involved :

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { HttpModule } from '@angular/http';
/* A lot of imports */

@NgModule({
  imports: [
    CommonModule,
    HttpModule,

  ],
  providers: [
    ApiService,
    CurrencyService,
    /* A lot of services */
    NbNotificationService
    ]
})

export class ServicesModule { }

This is the original module that is imported in App.module . What I through of is creating my own module like this :

import { ModuleWithProviders, NgModule, Optional, SkipSelf } from '@angular/core';

import { NbNotificationService } from './nb-notification.service';
@NgModule({
  providers:    [ NbNotificationService ]
})

export class NbNotificationServiceModule {
    constructor (@Optional() @SkipSelf() parentModule: NbNotificationServiceModule) {
        if (parentModule) {
          throw new Error(
            'NbNotificationServiceModule is already loaded. Import it in the AppModule only');
        }
      }

    static forRoot(): ModuleWithProviders {
        return {
          ngModule: NbNotificationServiceModule,
          providers: [
            {provide: NbNotificationService, useValue: 0 }
          ]
        };
      }
}

Tried to add this to AppModule but it says an error like : Cannot instantiate cyclic dependency! NbNotificationService ("[ERROR ->]"): in NgModule PagesModule in ./PagesModule@-1:-1

4

2 回答 2

2

If your services is provided in a lazy-loaded module and you want an application-wide singleton, you need to implement .forRoot() and provide the service there and import the module in AppModule with MyModule.forRoot.

Because DI contexts can't be modified after being created, lazy loaded modules get a new context for its providers and only this module and other modules loaded as part of it will be able to see the same instances of providers. AppModule, non-lazy loaded modules and other lazy-loaded modules will get no or a different instance.

See also https://angular.io/guide/singleton-services#forroot

于 2018-03-12T09:20:08.910 回答
0

Since you have your notifications in your service, why not simply using a getter ?

notification.service.ts

notifications: Notification[];

header.component.ts

get totalNotifications() { return this.notificationService.notifications.length; }
于 2018-03-12T08:51:19.573 回答