如何在没有父子关系的两个组件之间进行通信?

时间:2017-02-16 16:09:42

标签: angular angular-material

app.component.ts是我的Angular 2应用程序的入口点。它包含两个组件:标题和sidenav

@Component({
  selector: 'app-root',
  template: `
    <app-header></app-header>

    <app-sidenav></app-sidenav>
  `
})
export class AppComponent { }

这就是我想要实现的目标:在<app-header>组件内部,我有一个(菜单)按钮,它应该触发<app-sidenav>组件的打开。

换句话说,<app-header>按钮上的点击事件应触发open()组件内的<app-sidenav>方法。

  • header.component.ts

    @Component({
      selector: 'app-header',
      template: `
        <button (click)="onSidenavOpen()">Menu</button>
      `
    })
    export class HeaderComponent {
      constructor() { }
    
      onSidenavOpen() {
        // trigger the opening of the <app-sidenav> component
      }
    }
    
  • sidebar.component.ts

    @Component({
      selector: 'app-sidenav',
      template: `
        <md-sidenav #sidenav>
          // bla bla, sidebar
        </md-sidenav>
      `
    })
    export class SidenavComponent {
      constructor() { }
    
      open(sidenav) {
        sidenav.open();
      }
      close(sidenav) {
        sidenav.close();
      }
    }
    

我在Angular 2文档中阅读了component interaction section,但我很难找到在这两个组件之间进行通信的最佳方法。我的一般意图是为每个组件封装尽可能多的逻辑。

你如何处理我的用例?你会创建一个中间服务吗?请分享一个例子。

1 个答案:

答案 0 :(得分:4)

您可以使用服务允许两个单独的组件相互通信。在下面的示例中,HeaderComponent使用Observable的{​​{1}}方法将值推送到公开的toggleSideNavSidebarService在初始加载时订阅此SidenavComponent,并将响应推送的新值。

<强> SidebarService:

Observable

<强> HeaderComponent:

import { Injectable } from "@angular/core"

import { Observable, Subject } from "rxjs/Rx";

@Injectable()
export class SidebarService {

    private sidenavOpenSubject : Subject<boolean>;

    constructor() {
        this.sidenavOpenSubject = new Subject<boolean>();
    }

    toggleSideNav(opening: boolean): void {
        this.sidenavOpenSubject.next(opening);
    }

    onSideNavToggle(): Observable<boolean> {
        return this.sidenavOpenSubject;
    }

}

<强> SidebarComponent:

@Component({
  selector: 'app-header',
  template: `
    <button (click)="onSidenavOpen()">Menu</button>
  `
})
export class HeaderComponent {
  constructor(private sidebarService: SidebarService) { }

  onSidenavOpen() {
    this.sidebarService.toggleSideNav(true);
  }
}

@Component({ selector: 'app-sidenav', template: ` <md-sidenav #sidenav> // bla bla, sidebar </md-sidenav> ` }) export class SidenavComponent implements OnInit { constructor(private sidebarService: SidebarService) { } ngOnInit(): void { this.sidebarService.onSideNavToggle().subscribe( (opening) => { if (opening) { //Logic to open the sidenav here } else { //Logic to close the sidenav here } } ); } open(sidenav) { sidenav.open(); } close(sidenav) { sidenav.close(); } } 需要在合适的模块中注册(例如您的SidebarService)。