如何在Angular2的特定路线上操纵组件 [英] How to manipulate a component on specific routes in Angular2

查看:67
本文介绍了如何在Angular2的特定路线上操纵组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个简单的TopbarComponent,它基本上在视图顶部添加了引导式导航栏.

I have a simple TopbarComponent which basically adds a bootstrapish navbar at the top of my view.

由于90%的模板都应包含此指令,因此我想通过我的app.component来处理它,如下所示:

Since 90% of my templates should have this directive included, i want to handle it through my app.component which looks like this:

import ...;

@Component({
    selector: 'my-app',
    templateUrl: 'app/app.component.html',
    directives: [ROUTER_DIRECTIVES, TopbarComponent, ...],
    providers: [ROUTER_PROVIDERS, ...]
})

@RouteConfig([
{
    path: '/login',
    name: 'Login',
    component: LoginComponent
},
{
    path: '/dashboard',
    name: 'Dashboard',
    component: DashboardComponent,
    useAsDefault: true
}
])

其模板如下所示:

<my-topbar></my-topbar>

<div class="container-fluid">
    <div class="row">
        <router-outlet></router-outlet>
    </div>
</div>

现在,我想使用ngIf(或用css隐藏它以外的任何其他方式)来隐藏多条路线上的顶部栏,例如/login. 我尝试了几种使用@CanAcitvate()或在LoginComponent中实现OnActivate的方法(以及从AppComponent中尝试的方法),但是没有任何效果(甚至无法启动函数也有问题). 我最近得到的是像这样直接在我的AppComponent中使用Router:

Now i want use ngIf (or any other way except of hiding it with css) to hide the topbar on several routes, like /login for example. I tried several approaches using @CanAcitvate() or implementing OnActivate in my LoginComponent (as well as trying it from my AppComponent) but with no effects (having problems to even get the functions to fire). The closest i got was using the Router directly in my AppComponent like this:

export class AppComponent implements OnInit{
    showTopbar:boolean;

    constructor(private _router:Router) {}

    ngOnInit():any {
        this.showTopbar = this._router.lastNavigationAttempt != '/login';
    }
}

在我的app.component.html中,我将指令更改为<my-topbar *ngIf="showTopbar"></my-topbar>

and in my app.component.html i changed the directive to <my-topbar *ngIf="showTopbar"></my-topbar>

但这仅适用于我的应用程序的初始加载,原因是不会在每次状态更改时触发ngOnInit.我可以使用(但找不到)类似的方法还是在这里朝错误的方向前进?

But this only works on initial load of my app, cause ngOnInit isn't fired on each state change. Is there a similar method i can use (and just can't find) or am i moving in the wrong direction here?

目前,PierreDuc的答案对我不起作用,但是我尝试使用location.path()这样的类似方法:

At the moment, the answer of PierreDuc doesn't work for me, but i tried a similar approach using location.path() like this:

constructor(private _location:Location) {}

private get _hideTopbar() : boolean {
    switch(this._location.path()){
        case '/register':
        case '/login':
            return true;
        default:
            return false;
    }
};

太糟糕了,我无法以这种方式使用@RouteConfig中的data属性.会感觉更好.

Too bad that i can't use the data property in the @RouteConfig in this approach. It would feel better.

推荐答案

一段时间以来,我在类似问题上陷入了困境. 起初,我发现的解决方案似乎有些棘手,但将来可以为我解决许多类似的问题.

I've crashed my head on a similar problem for a while. The solution that i've found could be seen as tricky at first, but can resolve many similar problems of this type for me in the future.

基本上,您必须使router-outlet在路由更改时发出事件,让您的AppComponent监听该自定义事件.

Basically, you have to make the router-outlet emit an event on route change, having your AppComponent listening to that custom event.

第一步是创建自定义路由器出口:

The first step is to create a custom router-outlet:

@Directive({
selector: 'custom-router-outlet'
})
export class CustomRouterOutlet extends RouterOutlet {
    private parentRouter:Router;

    constructor(_elementRef: ElementRef,
            _loader: DynamicComponentLoader,
            _parentRouter: Router,
            @Attribute('name') nameAttr: string) {
    super(_elementRef, _loader, _parentRouter, nameAttr);
    this.parentRouter = _parentRouter;
    }

    activate(nextInstruction: ComponentInstruction): Promise<any> {
        //***YOUR CUSTOM LOGIC HERE***
        return super.activate(nextInstruction);
    }
}

这是自定义路由器插座的非常基本的实现.您的逻辑必须在 activate 方法中实现,该方法在每次更改路线时都会调用. 通过这种方法,您可以检查路线中的data属性.

This is a very basic implementation of a custom router-outlet. Your logic have to be implemented in the activate method, called on each route change. In this method you can check the data property in your route.

主要问题是,指令目前无法发出事件...它们仅接受输入,不能触发任何输出...

The main problem is that, right now, Directives can't emit events... They accept only inputs, no outputs can be fired...

我找到了解决此问题的方法:使用EventEmitter创建一个 Service 用于组件和指令之间的通信:

I've found a workaround to this problem: creating a Service for communication between Components and Directives using EventEmitter:

@Injectable()
export class PubsubService {
    private _pubSubber: EventEmitter<any> = new EventEmitter();

    routeisChanging(obj:any) {
        this._pubSubber.emit(obj);
    }

    onRouteChanged() {
        return this._pubSubber;
    }
}

AppComponent 订阅onRouteChanged事件:

subscription:any;
constructor(private _pubsubService:PubsubService) {
    this.subscription = this._pubsubService.onRouteChanged().subscribe(data => {
        /**YOUR CUSTOM LOGIC HERE*/});
}

CustomRouterOutlet 在需要时在activate方法中触发事件:

The CustomRouterOutlet fires the event in the activate method when needed:

activate(nextInstruction: ComponentInstruction): Promise<any> {
    //***YOUR CUSTOM LOGIC HERE***
    this._pubsubService.routeisChanging(nextInstruction.routeData.data['hideTopbar']);
    return super.activate(nextInstruction);
}

通过这种方式,您可以使用任何逻辑轻松地实现路由器与AppComponent之间的通信.

In this way you can easily implement a communication between the router and the AppComponent, with any logic.

您必须记住要在应用程序的RootComponent中注入通讯服务.

You have to remember to inject the communication Service in the RootComponent of your app.

这篇关于如何在Angular2的特定路线上操纵组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆