简体   繁体   English

Angular 2可观察订阅不会触发

[英]Angular 2 observable subscription not triggering

I have an issue with a subscription to an observable not triggering. 我有一个订阅可观察不触发的问题。

I have a layout using the side nav layout directive looking like this: 我有一个使用侧面导航布局指令的布局,如下所示:

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

What I need to do is open the side nav from the component that the router-outlet is displaying. 我需要做的是从路由器插座显示的组件打开侧面导航。

One such component might look like this: 一个这样的组件可能如下所示:

@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");
    }

}

I have created a service that returns an observable like this: 我创建了一个返回如下observable的服务:

@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);
    }

}

Finally the code for the parent class (that belongs with the side nav layout HTML): 最后是父类的代码(属于侧面导航布局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");
    });
  }
}

Now my problem is that the subscription in the App component does not trigger, however, the subscription in the Home component (which is what the router-outlet displays) is triggered as expected. 现在我的问题是App组件中的订阅不会触发,但Home组件中的订阅(路由器插座显示的内容)会按预期触发。

Am I missing something here? 我在这里错过了什么吗?

I followed this guide: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service 我遵循了这个指南: https//angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service

The same service instance isn't being shared across your App and Home components because you have listed SidenavService as a provider for both. 您的App和Home组件之间未共享相同的服务实例,因为您已将SidenavService列为SidenavService的提供者。

When you define service provider in the providers entry of a Component decorator, that service is then available to that component and all of its children as a singleton, meaning the same instance of the service will be used. 当您在组件装饰器的providers条目中定义服务提供者时,该服务随后可用于该组件及其所有子组件作为单例,这意味着将使用该服务的相同实例。

If you redefine a provider in a child component, it will create a new instance of the service and will no longer share the same service instance as its parent/ancestor. 如果重新定义子组件中的提供程序,它将创建该服务的实例,并且将不再与其父/祖先共享相同的服务实例。

If you are using SidenavService in both App and Home components and need the same instance, you should only provide it in the App component and remove it from the providers entry of Home. 如果您在App和Home组件中使用SidenavService并且需要相同的实例,则应仅在App组件中提供它并将其从Home的providers条目中删除。

For more information on DI, have a read of the following links: https://angular.io/docs/ts/latest/guide/dependency-injection.html https://angular.io/docs/ts/latest/guide/hierarchical-dependency-injection.html 有关DI的更多信息,请阅读以下链接: https//angular.io/docs/ts/latest/guide/dependency-injection.html https://angular.io/docs/ts/latest/guide /hierarchical-dependency-injection.html

The issue is that contrary to other frameworks Angular doesn't seem to force Service s to be singletons by default. 问题在于,与其他框架相反,Angular似乎并没有强制Service s默认为单例

Thus what you encounter is a situation when you declared each Component of yours to have its own instance of the Service . 因此,当您声明自己的每个Component都拥有自己的Service实例时,您会遇到这种情况。 This results in each instance having different attributes ( toggle and toggleObs ). 这导致每个实例具有不同的属性( toggletoggleObs )。 Schematically: 示意图:

App -> SidenavService [ instance A ] App - > SidenavService [ 实例A ]

Home -> SidenavService [ instance B ] 首页 - > SidenavService [ 实例B ]

You need to change your declarations to match Singleton Services as described in Angular Documentation . 您需要更改声明以匹配单一服务 ,如Angular文档中所述 Which results in sharing only a single instance of a Service among all Components . 这导致在所有Components仅共享Service的单个实例。 Schematically: 示意图:

App -> SidenavService [ instance A ] App - > SidenavService [ 实例A ]

Home -> SidenavService [ instance A ] 首页 - > SidenavService [ 实例A ]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM