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

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

问题描述

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

因为我 90% 的模板都应该包含这个指令,所以我想通过我的 app.component 来处理它,它看起来像这样:

import ...;@成分({选择器:'我的应用',templateUrl: 'app/app.component.html',指令:[ROUTER_DIRECTIVES, TopbarComponent, ...],提供者:[ROUTER_PROVIDERS, ...]})@RouteConfig([{路径:'/登录',name: '登录',组件:登录组件},{路径:'/仪表板',name: '仪表板',组件:仪表板组件,useAsDefault: 真}])

其模板如下所示:

<div class="container-fluid"><div class="row"><路由器插座></路由器插座>

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

导出类 AppComponent 实现 OnInit{showTopbar:boolean;构造函数(私有_路由器:路由器){}ngOnInit():any {this.showTopbar = this._router.lastNavigationAttempt != '/login';}}

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

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

<小时>

目前,PierreDuc 的答案对我不起作用,但我尝试使用 location.path() 类似的方法,如下所示:

constructor(private _location:Location) {}私人获取 _hideTopbar() : 布尔 {开关(this._location.path()){案例/注册":案例/登录":返回真;默认:返回假;}};

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

解决方案

我在类似的问题上已经有一段时间了.我发现的解决方案起初可能会被视为棘手,但将来可以为我解决许多此类类似问题.

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

第一步是创建自定义路由器插座:

@Directive({选择器:'自定义路由器插座'})导出类 CustomRouterOutlet 扩展 RouterOutlet {私有父路由器:路由器;构造函数(_elementRef: ElementRef,_loader: 动态组件加载器,_parentRouter:路由器,@Attribute('name') nameAttr: string) {super(_elementRef, _loader, _parentRouter, nameAttr);this.parentRouter = _parentRouter;}activate(nextInstruction: ComponentInstruction): Promise{//***您的自定义逻辑在这里***返回 super.activate(nextInstruction);}}

这是自定义路由器插座的一个非常基本的实现.您的逻辑必须在 activate 方法中实现,在每次路由更改时调用.在此方法中,您可以检查路线中的数据属性.

目前的主要问题是,指令不能发出事件……它们只接受输入,不能触发任何输出……

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

@Injectable()导出类 PubsubService {private _pubSubber: EventEmitter= new EventEmitter();routeisChanging(对象:任何){this._pubSubber.emit(obj);}onRouteChanged() {返回 this._pubSubber;}}

AppComponent 订阅 onRouteChanged 事件:

订阅:任意;构造函数(私有_pubsubService:PubsubService){this.subscription = this._pubsubService.onRouteChanged().subscribe(data => {/**您的自定义逻辑在这里*/});}

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

activate(nextInstruction: ComponentInstruction): Promise{//***您的自定义逻辑在这里***this._pubsubService.routeisChanging(nextInstruction.routeData.data['hideTopbar']);返回 super.activate(nextInstruction);}

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

你必须记住在你的应用程序的 RootComponent 中注入通信服务.

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

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
}
])

with its template looking like this:

<my-topbar></my-topbar>

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

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';
    }
}

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

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?


Edit:

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

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.

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

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

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

The AppComponent subscribes to the onRouteChanged event:

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

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

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

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

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

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆