如何在Angular2中的router-outlet中触发事件

14

我有一个主要的app组件,其中包含

<div class="appComponent">
<div class="row nav navbar">
    <div class="col-sm-8 text-left nav logo">Manacola</div>
    <button class="col-sm-1  col-sm-offset-1  btn btn-primary openGraph" (click)="openGraph()">Graph</button>
    <button class="col-sm-1   btn btn-primary openGraph" *ngIf="loggedIn" (click)="logout()">Logout</button>
</div>
<router-outlet ></router-outlet>

我想从另一个登录组件发出数据。 关键是,当我在loginComponent中按下“登录”按钮时,我希望在appComponent中设置*ngIf="loggedIn"为“true”。 最好有类似这样工作的东西:

<router-outlet (isLogged) = 'loggedIn = $event' ></router-outlet>   
2个回答

23

您可以在呈现在router-outlet中的组件中定义@Output事件发射器。 按以下方式定义路由器输出。

*.html
<router-outlet (activate)="onActivate($event)"></router-outlet>

在你的组件中,你可以这样做。

onActivate(elementRef) {
    elementRef.<the @Output eventEmitter>.subscribe(event => {
        console.log(event);
    });
}

通过这种方法,您可以将事件发送到渲染路由出口的组件。这是因为@Output事件发射器是事件流,您可以订阅这些事件。


抱歉,当您路由到一个没有该eventEmitter的组件时会发生什么? - ALGDB
1
不错的发现。@ALGDB 如果你的组件没有输出,那么就不会有任何东西被发出,对吧。你只是订阅了从 RouterOutlet 发出的事件,这是从 Outlet 中使用的组件中发出的任何内容。你有点在利用被激活事件的发射,这相当聪明。 - Mattijs
1
这个功能是特定于Angular的某个版本吗?这个语法对我不起作用。 - Esten
“(activate)” 与按下“登录”按钮有什么关系? “(activate)” 只有在路由改变时才会触发,是吗? - Ron Inbar
@RonInbar,“(activate)”在路由匹配时触发,因此组件的目标被加载(在<router-outlet>内),而“(deactivate)”在路由不再匹配到组件目标时触发,您可以使用这两个事件修改“isLoggedIn”字段。 - Adir D
哎呀,小心尖括号啊朋友们...它们可能会让你出大问题...嘿嘿。 - BrunoElo

12

这是一个非常好用的小工具,它能帮助在Angular2应用程序中传递事件。请注意,你应该只在耦合度低的组件之间(例如router-outlet的父子组件)使用此类事件代理器来通信。

示例:

....
import { EventBrokerService, IEventListener } "EventBrokerService";

@Component({
    selector: "my-listening-component",
    template: `
        <div *ngIf="indicator">I am On!</div>
        <div *ngIf="!indicator">I am Off!</div>
    `
})
@Injectable()
export class MyListeningComponent implements OnDestroy {
    public indicator: boolean = false;
    private _myEventListener: IEventListener;
    constructor(private _eventBroker: EventBrokerService) {
        this._myEventListener = _eventBroker.listen<boolean>("my-event",(value:boolean)=>{
             this.indicator = value;
        });
    }
    public ngOnDestroy() {
        this._myEventListener.ignore();
    }
}

@Component({
    selector: "my-sending-component",
    template: `
        <button (click)="canYouHearMe(true)>Turn me on</Button>
        <button (click)="canYouHearMe(false)>Turn me off</Button>
    `
})
@Injectable()
export class MySendingComponent {
    constructor(private _eventBroker: EventBrokerService) {
    }
    public canYouHearMe(value:boolean) {
        _eventBroker.emit<boolean>("my-event",value);
    }
}

EventBrokerService.ts文件:

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

interface IEventListener {
    ignore() : void;
}
interface IBrokeredEventBase {
    name:string;
    emit( data: any ): void;
    listen( next: (data: any) => void ): IEventListener;
}
interface IBrokeredEvent<T> extends IBrokeredEventBase  {
    emit( data: any ): void;
    listen( next: (data: any) => void ): IEventListener;
}
class EventListener implements IEventListener {
    constructor( private _subscription: Subscription ) {
    }
    public ignore() : void {
        this._subscription.unsubscribe();
    }
}

class BrokeredEvent<T> implements IBrokeredEvent<T> {
    private _subject: Subject<T>;
    constructor( public name: string ) {
        this._subject = new Subject<T>();
    }
    public emit( data: T ): void {
        this._subject.next(data);
    }
    public listen(next: (value: T) => void): IEventListener {
        return new EventListener(this._subject.subscribe( next ));
    }
}
@Injectable()
export class EventBrokerService {
    private _events: { [name: string]: IBrokeredEventBase };
    constructor() {
        this._events = {};
    }
    public register<T>(eventName: string ) : BrokeredEvent<T> {
        var event = this._events[eventName];
        if ( typeof event === 'undefined' ) {
            event = this._events[eventName] = new BrokeredEvent<T>(eventName);
        }
        return event as BrokeredEvent<T>;
    }
    public listen<T>(eventName: string, next: (value: T) => void) : IEventListener {
        return this.register<T>(eventName).listen(next);
    }
    public emit<T>(eventName: string, data: T) : void {
        return this.register<T>(eventName).emit(data);
    }
}

不要忘记在您的angular2模块中将EventBrokerService注册为提供者。

接口IEventListener需要被导出,否则MyListeningComponent将无法看到它。 - jtate
IBrokeredEventBase被IBrokeredEvent扩展的目的是什么,为什么第二个接口很方便? - ingkevin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接