我正在尝试在Angular中实现类似委托模式的东西。 当用户单击nav-item时,我想调用一个函数,该函数然后发出一个事件,该事件应该由侦听该事件的其他组件处理。

下面是场景:我有一个导航组件:

import {Component, Output, EventEmitter} from 'angular2/core';

@Component({
    // other properties left out for brevity
    events : ['navchange'], 
    template:`
      <div class="nav-item" (click)="selectedNavItem(1)"></div>
    `
})

export class Navigation {

    @Output() navchange: EventEmitter<number> = new EventEmitter();

    selectedNavItem(item: number) {
        console.log('selected nav item ' + item);
        this.navchange.emit(item)
    }

}

下面是观察组件:

export class ObservingComponent {

  // How do I observe the event ? 
  // <----------Observe/Register Event ?-------->

  public selectedNavItem(item: number) {
    console.log('item index changed!');
  }

}

关键问题是,如何让观察组件观察问题中的事件?


当前回答

我找到了另一个解决方案,没有使用Reactivex服务。我其实很喜欢rxjx API,但我认为它在解决异步和/或复杂函数时最好。用这种方式使用它,对我来说太过分了。

我想你想要的是广播。只是这一点。我找到了这个解决方案:

<app>
  <app-nav (selectedTab)="onSelectedTab($event)"></app-nav>
       // This component bellow wants to know when a tab is selected
       // broadcast here is a property of app component
  <app-interested [broadcast]="broadcast"></app-interested>
</app>

 @Component class App {
   broadcast: EventEmitter<tab>;

   constructor() {
     this.broadcast = new EventEmitter<tab>();
   }

   onSelectedTab(tab) {
     this.broadcast.emit(tab)
   }    
 }

 @Component class AppInterestedComponent implements OnInit {
   broadcast: EventEmitter<Tab>();

   doSomethingWhenTab(tab){ 
      ...
    }     

   ngOnInit() {
     this.broadcast.subscribe((tab) => this.doSomethingWhenTab(tab))
   }
 }

这是一个完整的工作示例: https://plnkr.co/edit/xGVuFBOpk2GP0pRBImsE

其他回答

你可以使用任何一种:

行为主体:

行为主体是主体的一种类型,主体是一种特殊类型的可观察对象,它可以充当被观察对象和观察者 你可以像订阅其他可观察对象一样订阅消息,在订阅时,它会返回主题的最后一个值 由源可观察对象触发:

优点:在组件之间传递数据不需要亲子关系等关系。

导航服务

import {Injectable}      from '@angular/core'
import {BehaviorSubject} from 'rxjs/BehaviorSubject';

@Injectable()
export class NavService {
  private navSubject$ = new BehaviorSubject<number>(0);

  constructor() {  }

  // Event New Item Clicked
  navItemClicked(navItem: number) {
    this.navSubject$.next(number);
  }

 // Allowing Observer component to subscribe emitted data only
  getNavItemClicked$() {
   return this.navSubject$.asObservable();
  }
}

导航组件

@Component({
  selector: 'navbar-list',
  template:`
    <ul>
      <li><a (click)="navItemClicked(1)">Item-1 Clicked</a></li>
      <li><a (click)="navItemClicked(2)">Item-2 Clicked</a></li>
      <li><a (click)="navItemClicked(3)">Item-3 Clicked</a></li>
      <li><a (click)="navItemClicked(4)">Item-4 Clicked</a></li>
    </ul>
})
export class Navigation {
  constructor(private navService:NavService) {}
  navItemClicked(item: number) {
    this.navService.navItemClicked(item);
  }
}

观察组件

@Component({
  selector: 'obs-comp',
  template: `obs component, item: {{item}}`
})
export class ObservingComponent {
  item: number;
  itemClickedSubcription:any

  constructor(private navService:NavService) {}
  ngOnInit() {

    this.itemClickedSubcription = this.navService
                                      .getNavItemClicked$
                                      .subscribe(
                                        item => this.selectedNavItem(item)
                                       );
  }
  selectedNavItem(item: number) {
    this.item = item;
  }

  ngOnDestroy() {
    this.itemClickedSubcription.unsubscribe();
  }
}

第二种方法是向上的child -> parent的事件委托

使用@Input和@Output装饰器,父组件将数据传递给子组件,子组件通知父组件

回答:@Ashish Sharma。

你可以使用如上所述的行为主体,或者还有一种方法:

你可以这样处理EventEmitter: 首先添加一个选择器

import {Component, Output, EventEmitter} from 'angular2/core';

@Component({
// other properties left out for brevity
selector: 'app-nav-component', //declaring selector
template:`
  <div class="nav-item" (click)="selectedNavItem(1)"></div>
`
 })

 export class Navigation {

@Output() navchange: EventEmitter<number> = new EventEmitter();

selectedNavItem(item: number) {
    console.log('selected nav item ' + item);
    this.navchange.emit(item)
}

}

现在你可以像这样处理这个事件 让我们假设observer.component.html是Observer组件的视图

<app-nav-component (navchange)="recieveIdFromNav($event)"></app-nav-component>

然后在ObservingComponent.ts中

export class ObservingComponent {

 //method to recieve the value from nav component

 public recieveIdFromNav(id: number) {
   console.log('here is the id sent from nav component ', id);
 }

 }

我找到了另一个解决方案,没有使用Reactivex服务。我其实很喜欢rxjx API,但我认为它在解决异步和/或复杂函数时最好。用这种方式使用它,对我来说太过分了。

我想你想要的是广播。只是这一点。我找到了这个解决方案:

<app>
  <app-nav (selectedTab)="onSelectedTab($event)"></app-nav>
       // This component bellow wants to know when a tab is selected
       // broadcast here is a property of app component
  <app-interested [broadcast]="broadcast"></app-interested>
</app>

 @Component class App {
   broadcast: EventEmitter<tab>;

   constructor() {
     this.broadcast = new EventEmitter<tab>();
   }

   onSelectedTab(tab) {
     this.broadcast.emit(tab)
   }    
 }

 @Component class AppInterestedComponent implements OnInit {
   broadcast: EventEmitter<Tab>();

   doSomethingWhenTab(tab){ 
      ...
    }     

   ngOnInit() {
     this.broadcast.subscribe((tab) => this.doSomethingWhenTab(tab))
   }
 }

这是一个完整的工作示例: https://plnkr.co/edit/xGVuFBOpk2GP0pRBImsE

你需要在ObservingComponent的模板中使用Navigation组件(别忘了给Navigation组件添加一个选择器..ex的导航组件)

<navigation-component (navchange)='onNavGhange($event)'></navigation-component>

并在ObservingComponent中实现onNavGhange()

onNavGhange(event) {
  console.log(event);
}

最后一点…你不需要@ component中的events属性

events : ['navchange'], 

如果一个人想要遵循更面向响应式的编程风格,那么“一切都是流”的概念肯定会出现,因此,尽可能多地使用可观察对象来处理这些流。