如何在Angular2

时间:2016-04-23 17:55:47

标签: angular angular2-routing

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

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

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()中使用OnActivate或实施LoginComponent尝试了几种方法(以及从AppComponent尝试),但没有任何影响(甚至无法获得功能)开火)。 我得到的最接近的是直接在我的Router中使用AppComponent,如下所示:

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>

但这仅适用于我的应用的初始加载,因为每次状态更改都不会触发ngOnInit。是否有类似的方法我可以使用(并且找不到)或者我是否朝这个方向走错了?

编辑:

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

constructor(private _location:Location) {}

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

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

6 个答案:

答案 0 :(得分:5)

我已经在类似的问题上撞了一会儿。 我发现的解决方案起初可能会被视为棘手,但可以在将来为我解决此类问题。

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

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

@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 方法中实现,并在每次路由更改时调用。 在此方法中,您可以检查路径中的数据属性。

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

我找到了解决此问题的方法:使用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方法触发事件:

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

通过这种方式,您可以轻松地在路由器和AppComponent之间实现任何逻辑通信。

您必须记住在应用的RootComponent中注入通信服务。

答案 1 :(得分:4)

不确定这是否正确,但您可以在@RouteConfig()对象的data参数中添加任何数据。例如,您可以在Login hideTopbar设置@RouteConfig([{ path: '/login', name: 'Login', component: LoginComponent, data : {hideTopbar : true} }, //... ]) 对象的位置。如果应将其设置为true,则只需将其置于路径中:

警告,未经测试的代码:)

AppComponent

您可以在export class AppComponent { private get _hideTopbar() : boolean { return this._data.get('hideTopbar'); }; constructor(private _data:RouteData) {} } 类中访问此数据,如:

AppComponent

<my-topbar *ngIf="!_hideTopbar"></my-topbar> <div class="container-fluid"> <div class="row"> <router-outlet></router-outlet> </div> </div> 模板更改为:

\w*([a-zA-Z0-9]){3,}\w*

答案 2 :(得分:2)

几乎在那里,试试这个

<强>模板

<my-topbar *ngIf="shouldShowTopbar()">
</my-topbar>

应用组件

export class AppComponent implements OnInit{

    hideWhen: Array<string> = ['Login', 'Help', 'SomeOtherRoute'];
       // put all the route names where you want it hidden in above array

    constructor(private _router:Router) {}

    shouldShowTopbar() {
     return (hideWhen.indexOf(this._router.currentInstruction.component.routeName) > -1);
    }

}

答案 3 :(得分:0)

我有类似的问题。也许这不是最好的方式。但我这样解决了:

我创建了一个新组件。此组件处理需要导航栏的所有路径。其他路由由app.component处理。

以下是一些需要理解的代码:

app.component

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


@Component({
selector: 'my-app',
template: '<router-outlet></router-outlet>', 
})

export class AppComponent {}

此处为MyComponentWhoAddsNavbar

@RouteConfig([
    put your routes here who need a navbar
])

@Component({
    selector: '...',
    template: `
        <navbar></navbar>
        <router-outlet></router-outlet> 
    `,

 })

export class MyComponentWhoAddsNavbar{} 

答案 4 :(得分:0)

我在

工作
"@angular/common": "~2.1.0"

我解决此问题的方法是创建一个应用程序范围的数据对象global及其服务GlobalService。任何组件都可以subscribe()全局或部分全局对象。出于您的目的,您应该创建一个布尔属性isTopBar: true。您可以订阅<topBar>组件并使用该值进行切换。

isTopBar: boolean;

ngOnInit(){
  this._globalService.getIsTopBar().subscribe(isTopBar => this.isTopBar = isTopBar)
}

<my-topbar *ngIf="isTopBar"></my-topbar>

我发现这种“全球服务”的一大优势。是我可以将很多状态信息保存到我的后端。在你的例子中它不太有用,但你有一套内部标签的成像;您可以保存用户上次选择的选项卡,并在以后重新访问该页面时重新加载到该视图。

答案 5 :(得分:0)

这可能不是正确的方法,但它对我有用。它不是根据路径本身改变可见性,而是根据路线中显示的组件改变可见性。

我已经在使用服务为所有部分提供导航栏,等等,所以我认为它也可以告诉导航栏何时出现。

我基本上在此服务中创建了一个主题,通过一系列方法来确定它是否可见,以改变这种可见性。

@Injectable()
export class NavigationService {

  mobileNavbarIsVisible = true;
  mobileNavbarIsVisibleChanged = new Subject<boolean>();

  constructor() { }

  getSections() {
    return this.sections;
  }

  getMobileNavbarIsVisible() {
    return this.mobileNavbarIsVisible;
  }

  hideMobileNavbar() {
    this.mobileNavbarIsVisible = false;
    this.mobileNavbarIsVisibleChanged.next(this.mobileNavbarIsVisible);
  }

  showMobileNavbar() {
    this.mobileNavbarIsVisible = true;
    this.mobileNavbarIsVisibleChanged.next(this.mobileNavbarIsVisible);
  }

}

然后,我在影响可见性的组件中调用那些方法 - 在我的情况下,每当我编辑项目列表中的项目时,我希望导航栏消失 - 。我启动此组件时调用hide方法,并在销毁时调用show方法。

@Component({
  selector: 'app-item-edit',
  templateUrl: './item-edit.component.html',
  styleUrls: ['./item-edit.component.css']
})
export class ItemEditComponent implements OnInit, OnDestroy {

  constructor(private navigationService: NavigationService) {}
  ngOnInit() {
    this.navigationService.hideMobileNavbar();
  }
  ngOnDestroy() {
    this.navigationService.showMobileNavbar();
  }
}

然后,我的NavbarComponent正在收听该主题,只是根据该值显示或不显示:

@Component({
  selector: 'app-mobile-navbar',
  templateUrl: './mobile-navbar.component.html',
  styleUrls: ['./mobile-navbar.component.css']
})
export class MobileNavbarComponent implements OnInit {
  isVisible = true;
  ngOnInit() {
    this.isVisible = this.navigationService.getMobileNavbarIsVisible();
    this.navigationService.mobileNavbarIsVIsibleChanged.subscribe(
      (visibilityValue) => this.isVisible = visibilityValue
    );
  }
}

正如我所说,它很可能不是正确或最有效的方式,但如果您只想在启动其他组件时隐藏导航栏,它就有效,因为它们只是使用导航服务作为一种方式沟通。