Связь между компонентами службы не работает

Я использую класс BehaviorSubject для обновления количества уведомлений в моем файле global. У меня есть 2 компонента: уведомление компонента показывает список уведомлений, и вы можете установить эти уведомления как прочитанные. Компонент шапки показывает количество уведомлений, которые не прочитаны, чтобы дать пользователю понять, что он что-то пропустил на сайте. Поскольку есть 2 разных компонента, я использую сервис для связи через них.

Вот какой-то фрагмент:

уведомление.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();
} }

уведомление.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
}
}

Проблема в том, что даже если значение установлено на стороне уведомления.component.ts, значение, полученное в header.component.ts, не является хорошим и является исходным, ведь это не то, что я хочу, конечно.

У кого-нибудь есть идея? Боролся с этим слишком долго


Обновлять

Вот часть html, которая очень проста:

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

Обновление 2

В модуле участвовали:

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 { }

Это исходный модуль, который импортируется в App.module. Что я делаю, так это создаю свой собственный модуль следующим образом:

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 }
          ]
        };
      }
}

Пытался добавить это в AppModule, но выдает ошибку типа: Cannot instantiate cyclic dependency! NbNotificationService ("[ERROR ->]"): in NgModule PagesModule in ./PagesModule@-1:-1


person Nicolas S.    schedule 12.03.2018    source источник
comment
nbNotificationsChange не определено в вашем классе. Это нормально?   -  person    schedule 12.03.2018
comment
Кроме того, вы подписываетесь в ngOnInit(), но никогда не отписываетесь (у вас нет ngOnDestroy()), что вы должны делать.   -  person rrd    schedule 12.03.2018
comment
@trichetriche Упс, вот (обновлено), забыл включить в свой фрагмент   -  person Nicolas S.    schedule 12.03.2018
comment
@rrd idd, я тоже забыл. Но я пробовал разные подписки в разных местах, и результат тот же   -  person Nicolas S.    schedule 12.03.2018
comment
Обновлен html для header.component   -  person Nicolas S.    schedule 12.03.2018
comment
Где вы регистрируете службу уведомлений? Предоставляется ли он модулем или каждым компонентом?   -  person hagner    schedule 12.03.2018
comment
По модулю @hagner   -  person Nicolas S.    schedule 12.03.2018
comment
Модуль загружается лениво или жадно?   -  person Günter Zöchbauer    schedule 12.03.2018
comment
ленивый @GünterZöchbauer   -  person Nicolas S.    schedule 12.03.2018


Ответы (2)


Если ваши услуги предоставляются в модуле с отложенной загрузкой, и вам нужен синглтон для всего приложения, вам необходимо реализовать .forRoot() и предоставить службу там, а также импортировать модуль в AppModule с помощью MyModule.forRoot.

Поскольку контексты DI нельзя изменить после создания, лениво загруженные модули получают новый контекст для своих провайдеров, и только этот модуль и другие модули, загруженные как его часть, смогут видеть одни и те же экземпляры провайдеров. AppModule, модули без ленивой загрузки и другие модули с ленивой загрузкой не получат экземпляр или получат другой экземпляр.

См. также https://angular.io/guide/singleton-services#forroot.

person Günter Zöchbauer    schedule 12.03.2018
comment
Этот сервис зарегистрирован в глобальном модуле service.module.ts. как я могу применить .forRoot только к служебному уведомлению без собственного модуля? - person Nicolas S.; 12.03.2018
comment
Хм, документы немного хромают. Например, вы можете посмотреть источник RouterModule, где зарегистрированы все виды провайдеров github.com/angular/angular/blob/ и как он импортируется imports: [RouterModule.forRoot(ROUTES)] angular.io/api/router/RouterModule. Вам не нужен параметр ROUTES для вашего собственного модуля. - person Günter Zöchbauer; 12.03.2018
comment
Я не понимаю. Приведем пример: у меня есть NbNotificationService с моим значением, сеттер и геттер. Эта служба изначально импортируется в файл services.module.ts. Нужно ли мне создавать NbNotificationServiceModule для реализации forRoot или я могу сделать это напрямую с уже имеющимися у меня файлами? - person Nicolas S.; 12.03.2018
comment
Не могли бы вы добавить код (@NgModule(...) модулей, задействованных в вашей проблеме с соответствующим(и) провайдером(ами)) к вашему вопросу, а затем я добавлю исправленный пример к своему ответу, если обнаружу ошибку? - person Günter Zöchbauer; 12.03.2018
comment
Вам не нужно providers: [NbNotificationService, ...] где-либо еще, кроме forRoot(), это не повредит, если только в модулях, которые не лениво загружаются. Проблема циклической зависимости не зависит от проблемы синглтона. Мне нужно было бы увидеть больше кода, чтобы иметь возможность делать предложения. Можете ли вы попытаться сделать минимальное воспроизведение на stackblitz.com? Где и как вы импортируете NbNotificationServiceModule.forRoot()? - person Günter Zöchbauer; 12.03.2018
comment
Невозможно воспроизвести, не повредив разумный код. NbNotificationServiceModule.forRoot() импортируется в app.module.ts. Небольшое изменение, хотя этой циклической проблемы больше нет, но теперь мой объект равен useValue. Можно ли использовать это значение useValue для создания моего сервиса? - person Nicolas S.; 12.03.2018
comment
Невозможно воспроизвести, не повредив разумный код. Я не могу представить. Для этого не требуется ни одной строки реализации, только объявления классов и параметры конструктора. - person Günter Zöchbauer; 12.03.2018
comment
Я даже не заметил эту строчку с useValue. Не похоже, что это то, что вы намереваетесь. Когда вы запрашиваете NbNotificationService, вы получаете 0. Это действительно намерение? Если вы хотите вводить простые значения, вместо этого следует использовать InjectionToken angular.io/guide. / - person Günter Zöchbauer; 12.03.2018
comment
Idd, я хочу внедрить экземпляр моего сервиса в этот момент. Где я могу его создать? Я полагаю, я могу в том же файле сделать экспорт - person Nicolas S.; 12.03.2018
comment
Это хорошо, Injection решает все проблемы, которые у меня были! Большое спасибо за помощь! :D - person Nicolas S.; 12.03.2018
comment
Рад слышать :) - person Günter Zöchbauer; 12.03.2018

Поскольку у вас есть уведомления в вашем сервисе, почему бы просто не использовать геттер?

уведомление.service.ts

notifications: Notification[];

header.component.ts

get totalNotifications() { return this.notificationService.notifications.length; }
person Community    schedule 12.03.2018
comment
Дело в том, что у меня в сервисе нет уведомлений. Этот сервис позволяет мне обрабатывать некоторые ошибки, если они случаются, и создавать объект уведомления в notification: BehaviorSubject<Object> - person Nicolas S.; 12.03.2018
comment
Затем используйте геттер с переменной, содержащей ваши уведомления, и, если вам нужно поделиться ею между компонентами, создайте для этого службу - person ; 12.03.2018
comment
В новом сервисе моя переменная все еще должна быть SubjectBehavior или она может быть обычной? - person Nicolas S.; 12.03.2018
comment
Нет, пусть это будет обычный, так будет намного проще! - person ; 12.03.2018