web-dev-qa-db-ja.com

Angular2:ルートを使用して、正常にログインした後にナビゲーションバーを表示する方法

ユーザーが成功したら、ナビゲーションバーを表示しようとしています。

例えば:

「LoginComponent」内の「AppComponent」の「showMenu」プロパティを変更するには?重要:ルートを使用しています。

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:

@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']);

  }
}

それとも、この設計はそれを解決する最善の方法ではありませんか?

21
NereuJunior

私は最近似たようなことをしました、そしてここに私がそれをした方法があります。まず、アプリのルートにNavBarComponentを作成する必要があります。そしてNavBarComponentでは、必要な場所に注入するサービスである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);
    }


}

次に、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']);

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

 
}

アプリコンポーネントは次のようになります。

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

また、アプリを起動するときにGlobalEventsManagerを登録する必要があります。

import { GlobalEventsManager } from './GlobalEventsManager';
import { TopNavbarComponent } from './TopNavbarComponent';

@NgModule({
    bootstrap: [App],
    declarations: [
        App,
        TopNavbarComponent
    ],
    imports: [
        BrowserModule
    ],
    providers: [GlobalEventsManager]
})
export class AppModule {
}

それはそれを行う必要があります。

更新:コンポーネントの外部、つまりサービスでイベントを使用するより受け入れられた方法を反映するために、この回答を更新しました。 EventEmitterの代わりにBehaviorSubject/Observableを使用する必要があります

36
brando

実際には、イベントエミッタ/リスナーを使用しないまったく異なるアプローチがあります。私はイベントに何も反対せず、特定のプロジェクトのニーズ/複雑さに応じて、両方のアプローチ(下のアプローチと@brandoのアプローチ)を使用します。

メソッド:2つのアプリケーションモジュール(領域)があります:public(navbarを持たない)とprotected(1つを持つ)です。

パブリックモジュールにはすべてのパブリックルートが含まれます。

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

これはあなたがすでに持っているべきものであり、ここでは珍しいことは何もありません。

それから保護区域があります

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

そしてここから魔法が始まります。

まず、point 1に注意してください:

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

これが必要ですここ。 AppModuleに配置すると、無視されます。ここで重要なことは何もありません。保護されたモジュールでこのリダイレクトを行うことはさらに論理的かもしれません。

ポイント2を使用すると、すべての子のレンダリングを処理するNavbarWrapperComponentポイント)にすべての子ルートをプロキシできます。 navbarコンポーネントのテンプレートは次のとおりです。

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

<router-outlet></router-outlet>

この<router-outlet>は、すべての子ルートを処理します。

あなたが直面する可能性のある問題とその解決策:

  • AppModuleへのリダイレクトを配置することもできます。point 2のパスを実際の名前に変更するだけです。 protected。これにより、保護されたすべてのURLにこの値がプレフィックスとして追加されますが、これは望ましくない場合があります。 2つのオプションを選択できます。
  • 保護された領域内に複数のモジュールを配置したい場合があります- lazy routing を使用します
  • ナビゲーションを非表示/表示したり、パラメータを渡したりすることができます-イベントソリューションと組み合わせてください。

この方法はそれほど柔軟ではないように思えるかもしれませんが、実際に機能し、必要な場合のほぼすべてのケースをカバーします。イベントの複雑さはなく、Router機能を完全に利用します。ここでのキラーなこと-それは愚かでシンプルで、理解と保守が非常に簡単です。

4
smnbbrv

angular4の最新の最適な方法で、新しいルーターを使用し、子ルートを使用し、UrlSerializerクラスを使用してかっこを削除するだけでした 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: '' }
]
0
stackdave