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
Если вы вводите название Сервиса на каждый компонент. Это может не сработать. Поэтому, пожалуйста, будьте осторожны.