Angular 2 наблюдаемых подписки не запускаются

У меня есть проблема с подпиской на наблюдаемое не срабатывание.

У меня есть макет, используя директиву side nav layout, которая выглядит так:

<md-sidenav-layout class="nav-bar">


    <md-sidenav #start>
        <nav>
            <a [routerLink]="['/home']">Home</a>
        </nav> 
        <button md-button (click)="start.close()">Close</button>
    </md-sidenav>

    <router-outlet></router-outlet>

</md-sidenav-layout>

Что мне нужно сделать, так это открыть боковой навигатор из компонента, отображаемого маршрутизатором.

Один из таких компонентов может выглядеть так:

@Component({

    providers: [SidenavService, MdIconRegistry],
    directives: [MdIcon],
    templateUrl: `<md-icon (click)="toggleSidenav()">menu</md-icon>`,
    styleUrls: ["./home.component.scss"]
})

export class Home {

    myColor: string;

    constructor(private sidenavService: SidenavService) {
        this.myColor = "primary";

        this.sidenavService.getSidenavObs().subscribe(state => {console.log("state change")});
    }


    toggleSidenav() {

        this.sidenavService.toggleSidenav("open");
    }

}

Я создал службу, которая возвращает видимый вид:

@Injectable()
export class SidenavService {

    private toggle = new Subject<string>();
    private toggleObs = this.toggle.asObservable();

    getSidenavObs() {
        return this.toggleObs;
    }

    toggleSidenav(state: string) {
        this.toggle.next(state);
    }

}

Наконец, код для родительского класса (который принадлежит боковому макету HTML):

@Component({
  providers: [MdSidenav, SidenavService],
  directives: [ROUTER_DIRECTIVES, MD_SIDENAV_DIRECTIVES, MD_BUTTON_DIRECTIVES],
  selector: "app",
  templateUrl: "app.html",
  styleUrls: ["./app.scss"],
})

export class App {

  subscription: Subscription;

  constructor(private sidenavService: SidenavService, private sidenav: MdSidenav) {
    this.subscription = sidenavService.getSidenavObs().subscribe( status => {
      console.log("state change");
      sidenav.open();
    }, error => {
      console.log(error);
    }, () => {
      console.log("completed");
    });
  }
}

Теперь моя проблема заключается в том, что подписка в компоненте App не запускается, однако подписка в домашнем компоненте (который отображается на дисплее маршрутизатора) запускается, как ожидалось.

Я что-то пропустил?

Я последовал этому руководству: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

Ответ 1

Тот же экземпляр службы не используется совместно с вашими компонентами App и Home, потому что вы указали SidenavService в качестве поставщика для обоих.

Когда вы определяете поставщика услуг в записи providers декоратора Component, эта служба затем доступна для этого компонента и всех его дочерних элементов в качестве одноэлементного значения, что означает, что будет использоваться тот же экземпляр службы.

Если вы переопределите поставщика в дочернем компоненте, он создаст новый экземпляр службы и больше не будет использовать тот же экземпляр службы, что и его родитель/предок.

Если вы используете SidenavService в компонентах App и Home и нуждаетесь в том же экземпляре, вы должны предоставить его только в компоненте App и удалить его из записи providers дома.

Для получения дополнительной информации о DI, прочитайте следующие ссылки: https://angular.io/docs/ts/latest/guide/dependency-injection.html https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html

Ответ 2

Проблема в том, что в отличие от других сред Angular, по-видимому, не заставляет Service быть одиночками по умолчанию.

Таким образом, вы сталкиваетесь с ситуацией, когда вы заявляете, что каждый ваш Component имеет свой собственный экземпляр Service. Это приводит к тому, что каждый экземпляр имеет разные атрибуты (toggle и toggleObs). Схематично:

Приложение → SidenavService [ экземпляр A ]

Дома → SidenavService [ экземпляр B ]

Вам необходимо изменить декларации, чтобы они соответствовали Singleton Services, как описано в Angular Documentation. Что приводит к совместному использованию только одного экземпляра Service среди всех Components. Схематично:

Приложение → SidenavService [ экземпляр A ]

Дома → SidenavService [ экземпляр A ]

Ответ 3

Если вы вводите название Сервиса на каждый компонент. Это может не сработать. Поэтому, пожалуйста, будьте осторожны.