简体   繁体   English

Angular2:使用路由,如何在成功登录后显示导航栏?

[英]Angular2: Using routes, how to display the navigation bar after successfully logged in?

I'm trying to show the navigation bar, once the user successfully do. 一旦用户成功完成,我正在尝试显示导航栏。

For example: 例如:

How To Change "showMenu" property in "AppComponent" inside the "LoginComponent"? 如何在“LoginComponent”中的“AppComponent”中更改“showMenu”属性? Important: I am using routes. 重要提示:我正在使用路线。

app.ts: app.ts:

@Component({
  selector: 'app',
  template: `<div *ngIf="showMenu">
               <fnd-menu-nav></fnd-menu-nav>
             </div>
             <router-outlet></router-outlet>
              `,
  directives: [ROUTER_DIRECTIVES, MenuNavComponent]
})
@RouteConfig([
  { path: '/login', name: 'Login', component: LoginComponent, useAsDefault: true },
  { path: '/welcome', name: 'Welcome', component: WelcomeComponent }
])
export class AppComponent {
  public showMenu : boolean;
}

login.component.ts: login.component.ts:

@Component({
  selector: 'fnd-login',
  templateUrl: './fnd/login/components/login.component.html',
  providers: [LoginService]
})
export class LoginComponent {
  /* .. other properties */

  constructor(private _router: Router, private _loginService: LoginService ) {
  }
  /* .. other methods  */
  /* .. other methods  */


  private onLoginSuccessfully(data : any) : void {
    /* --> HERE: Set showMenu in AppComponent to true. How? */
    this._router.navigate(['Welcome']);

  }
}

Or this design is not the best way to solve it? 或者这种设计不是解决它的最佳方法?

I recently did something similar and here is how I did it. 我最近做了类似的事情,这是我做的。 First, you need to create a NavBarComponent at the root of your app. 首先,您需要在应用程序的根目录下创建一个NavBarComponent。 And in the NavBarComponent you reference (what I call) a GlobalEventsManager which is a service that you inject where you need it. 在NavBarComponent中,您引用(我称之为)GlobalEventsManager,这是您在需要的地方注入的服务。

Here is a look at the GlobalEventsManager: 以下是GlobalEventsManager:

 import { Injectable } from '@angular/core'; import { BehaviorSubject } from "rxjs/BehaviorSubject"; import { Observable } from "rxjs/Observable"; @Injectable() export class GlobalEventsManager { private _showNavBar: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); public showNavBarEmitter: Observable<boolean> = this._showNavBar.asObservable(); constructor() {} showNavBar(ifShow: boolean) { this._showNavBar.next(ifShow); } } 

Now you inject the GlobalEventsManger service into your login component (something like this) 现在您将GlobalEventsManger服务注入到您的登录组件中(类似这样)

 import {GlobalEventsManager} from "./../GlobalEventsManager"; @Component({ selector: 'fnd-login', templateUrl: './fnd/login/components/login.component.html', providers: [LoginService] }) export class LoginComponent { /* .. other properties */ constructor(private _router: Router, private _loginService: LoginService, private globalEventsManager: GlobalEventsManager) { } /* .. other methods */ /* .. other methods */ private onLoginSuccessfully(data : any) : void { /* --> HERE: you tell the global event manger to show the nav bar */ this.globalEventsManger.showNavBar(true); this._router.navigate(['Welcome']); } } 
In your NavBarComponent you subscribe to the showNavBar Event Emitter: 在您的NavBarComponent中,您订阅了showNavBar事件发射器:

 import {Component, OnInit} from "@angular/core"; import {GlobalEventsManager} from "../GlobalEventsManager"; @Component({ selector: "navbar", templateUrl: "app/main/topNavbar/TopNavbar.html" }) export class TopNavbarComponent { showNavBar: boolean = false; constructor(private globalEventsManager: GlobalEventsManager) { this.globalEventsManager.showNavBarEmitter.subscribe((mode)=>{ this.showNavBar = mode; }); } } 
use *ngIf="showNavBar" in the template HTML to hide/show the Nav bar. 在模板HTML中使用* ngIf =“showNavBar”来隐藏/显示导航栏。

Your app component then looks something like this: 您的应用程序组件看起来像这样:

 @Component({ selector: 'app', template: `<navbar></navbar> <router-outlet></router-outlet> ` }) export class AppComponent { //This doesn't belong here --> public showMenu : boolean; } 

Also the GlobalEventsManager must be registered when you boot the app: 此外,在启动应用程序时必须注册GlobalEventsManager:

 import { GlobalEventsManager } from './GlobalEventsManager'; import { TopNavbarComponent } from './TopNavbarComponent'; @NgModule({ bootstrap: [App], declarations: [ App, TopNavbarComponent ], imports: [ BrowserModule ], providers: [GlobalEventsManager] }) export class AppModule { } 

That should do it. 应该这样做。

UPDATE: I have updated this answer to reflect the more accepted way of using events outside of a component, ie in a service; 更新:我已更新此答案,以反映在组件外部使用事件的更可接受的方式,即在服务中; which entails using BehaviorSubject/Observable instead of EventEmitter 这需要使用BehaviorSubject / Observable而不是EventEmitter

Actually there is a totally different approach that does not use any of event emitters / listeners. 实际上有一种完全不同的方法,它不使用任何事件发射器/监听器。 I have nothing against the events and I use both approaches (the below one and @brando's one) according to the particular project needs / complexity. 我没有反对这些事件,我根据特定的项目需求/复杂性使用两种方法(下面一种和@ brando的方法)。

The method: we have 2 application modules (areas): public (that has no navbar) and protected (the one that has one). 方法:我们有2个应用程序模块(区域):public(没有navbar)和protected(有一个)。

Public module contains all public routes: 公共模块包含所有公共路由:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { LoginComponent } from './login/login.component';
import { RegistrationComponent } from './registration/registration.component';
import { ResetPasswordComponent } from './reset-password/reset-password.component';

@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild([
      { path: 'login', component: LoginComponent },
      { path: 'registration', component: RegistrationComponent },
      { path: 'reset-password', component: ResetPasswordComponent }
    ])
  ],
  declarations: [
    LoginComponent,
    RegistrationComponent,
    ResetPasswordComponent
  ]
})
export class PublicModule { }

This is what you already should have, there is nothing unusual here. 这是你应该拥有的,这里没有什么不寻常的。

Then we have a protected area 然后我们有一个保护区

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { NavbarWrapperComponent } from './navbar-wrapper/navbar-wrapper.component';
import { UserProfileComponent } from './user-profile/user-profile.component';

@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild([
      { path: '', redirectTo: '/login', pathMatch: 'full' }, // point 1
      {
        path: '', // point 2
        component: NavbarWrapperComponent, // point 3
        children: [
          { path: 'profile', component: UserProfileComponent }
        ]
      }
    ])
  ],
  declarations: [
    NavbarWrapperComponent,
    UserProfileComponent
  ]
})
export class ProtectedModule { }

and here the magic starts. 这里的魔法开始了。

First of all, pay attention to the point 1 : 首先,要注意第1点

{ path: '', redirectTo: '/login', pathMatch: 'full' },

We need this right here . 我们在这里需要这种权利 If we put it to the AppModule it will be ignored. 如果我们将它放到AppModule中,它将被忽略。 There is nothing crucial here, it might be even more logical to have this redirect in the protected module. 这里没有什么关键,在受保护的模块中进行此重定向可能更合乎逻辑。

Point 2 allows us to proxy all the children routes into the NavbarWrapperComponent ( point 3 ) which takes care of rendering of all our children. Point 2允许我们将所有子路径代理到NavbarWrapperComponent第3点 ),它负责渲染我们所有的孩子。 Here is a navbar component's template: 这是一个导航栏组件的模板:

<nav class="navbar navbar-toggleable-md navbar-light bg-faded">
  <!-- nav content here -->
</nav>

<router-outlet></router-outlet>

This <router-outlet> will handle all the children routes. <router-outlet>将处理所有子路由。

Possible problems you might face and their solution: 您可能遇到的问题及其解决方案:

  • you might want to put the redirect to the AppModule - just change the path in the point 2 to be some real name eg protected . 您可能希望将重定向放到AppModule - 只需将第2点中的路径更改为某个实名,例如protected This will prefix all of your protected urls with this value, which you might not want. 这将为您的所有受保护网址添加此值,您可能不需要此值。 You have 2 options to choose. 您有2个选项可供选择。
  • you might want to have more than just one module inside of the protected area - just use lazy routing 您可能希望在受保护区域内只有一个模块 - 只需使用延迟路由
  • you might want to hide / show the navigation, pass parameters etc. - just combine it with the events solution. 你可能想隐藏/显示导航,传递参数等 - 只需将它与事件解决方案结合起来。

This way might seem not that flexible, however it really works and covers nearly all the cases you might need. 这种方式可能看起来不那么灵活,但它确实有效并涵盖了您可能需要的几乎所有情况。 It does not have the events complexity and fully utilises the Router features. 它没有事件复杂性并充分利用Router功能。 The killer thing here - it is dumb simple and very easy to understand and maintain. 这里的杀手锏 - 它简单易懂,易于理解和维护。

best modern way in angular4, with new router, with children routes, just needed use UrlSerializer-class to remove parenthesis, https://angular.io/docs/ts/latest/api/router/index/UrlSerializer-class.html , anyone did uses it? angular4中最好的现代方式,带有新的路由器,带有子路径,只需要使用UrlSerializer-class删除括号, https: //angular.io/docs/ts/latest/api/router/index/UrlSerializer-class.html,有人用它吗?

export const ROUTES: Routes = [
  { path: 'login', component: LoginComponent },
  {
    path : '',
    children: [
        {
          path: '', component: DefaultLayoutComponent,
          children: [
            { path: '', component: HomeComponent, canActivate: [AuthGuard] },
            { path: 'users', component: UsersListComponent, canActivate: [AuthGuard] },
            { path: 'users-add', component: UsersAddComponent, canActivate: [AuthGuard] },
            { path: 'users-view/:id', component: UsersViewComponent, canActivate: [AuthGuard] },
            { path: 'users-edit/:id', component: UsersEditComponent, canActivate: [AuthGuard] },
            ]
        }
    ]
  },
  // otherwise redirect to home
  { path: '**', redirectTo: '' }
]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM