Angularでルート変更を検出するにはどうすればよいですか?


428

のルート変更を検出しようとしていAppComponentます。

その後、グローバルユーザートークンをチェックして、彼がログインしているかどうかを確認します。ログインしていない場合は、ユーザーをリダイレクトできます。

回答:


534

Angular 2ではsubscribe、ルーターインスタンスに(Rxイベント)できます。だからあなたは次のようなことができます

class MyClass {
  constructor(private router: Router) {
    router.subscribe((val) => /*whatever*/)
  }
}

編集(rc.1以降)

class MyClass {
  constructor(private router: Router) {
    router.changes.subscribe((val) => /*whatever*/)
  }
}

編集2(2.0.0以降)

参照:Router.eventsドキュメント

class MyClass {
  constructor(private router: Router) {
    router.events.subscribe((val) => {
        // see also 
        console.log(val instanceof NavigationEnd) 
    });
  }
}

2
私はevent._root.children[0].value._routeConfig.dataより良い方法があることを望んでデータを取得できます
Akshay

6
@Akshayは、Todd Mottoによるこの記事を見ました:[Angular 2の動的ページタイトルとルーターイベント](toddmotto.com/dynamic-page-titles-angular-2-router-events
Bogac

10
なぜ3回発砲するのですか?
ツールキット

2
@Toolkitは、イベントに3つの状態があり、URLが正常に変更されたためです。3つの状態は次のとおりです。「NavigationStart」、「NavigationEnd」、「RoutesRecognized」
RicardoGonzales

10
RxJS filterオペレーターでイベントを簡単にフィルターできます。router.events.pipe(filter(e => e instanceof NavigationEnd).subscribe((e) => { ... }
Simon_Weaver 2018

314

RxJS 6

router.events.pipe(filter(event => event instanceof NavigationStart))

Peilonrayzに感謝(下記のコメントを参照)

新しいルーター> = RC.3

import { Router, NavigationStart, NavigationEnd, NavigationError, NavigationCancel, RoutesRecognized } from '@angular/router';

constructor(router:Router) {
  router.events.forEach((event) => {
    if(event instanceof NavigationStart) {
    }
    // NavigationEnd
    // NavigationCancel
    // NavigationError
    // RoutesRecognized
  });
}

特定のイベントでフィルタリングすることもできます。

import 'rxjs/add/operator/filter';

constructor(router:Router) {
  router.events
    .filter(event => event instanceof NavigationStart)
    .subscribe((event:NavigationStart) => {
      // You only receive NavigationStart events
    });
}

pairwise演算子を使用して前のイベントと現在のイベントを取得するのも良い考えです。https://github.com/angular/angular/issues/11268#issuecomment-244601977

import 'rxjs/add/operator/pairwise';
import { Router } from '@angular/router;

export class AppComponent {
    constructor(private router: Router) {
        this.router.events.pairwise().subscribe((event) => {
            console.log(event);
        });
    };
}

1
@isではなく@GunterZochbauerを使用すると、instanceofが使用されます。また、「イベント:イベント」は括弧内にある必要があります。これをありがとう、かなり強力な新機能!気に入った
マキシム

2
これは、現在のバージョンでコンパイルエラーをスローしますArgument of type '(event: Event) => void' is not assignable to parameter of type
Rudi

1
@RudiStrydom&GünterZöchbauer- Argument of type '(event: Event) => void' is not assignable to parameter of typeフィルタースニペットで、NavigationEventではなくEventタイプのオブジェクトをサブスクライブしているため、エラーが発生します。
Bonnici

1
2番目のサンプルは、EventではなくNavigationEventである必要があります。また、@ angular / routerから「Event as NavigationEvent」をインポートすることを忘れないでください
Mick

1
インポートに関するヒントは、このエラーを解決しようとしている人向けです:)
Mick

92

ために 角度7誰かが風に記述する必要があります。

this.router.events.subscribe((event: Event) => {})


詳細な例は次のとおりです。

import { Component } from '@angular/core'; 
import { Router, Event, NavigationStart, NavigationEnd, NavigationError } from '@angular/router';

@Component({
    selector: 'app-root',
    template: `<router-outlet></router-outlet>`
})
export class AppComponent {

    constructor(private router: Router) {

        this.router.events.subscribe((event: Event) => {
            if (event instanceof NavigationStart) {
                // Show loading indicator
            }

            if (event instanceof NavigationEnd) {
                // Hide loading indicator
            }

            if (event instanceof NavigationError) {
                // Hide loading indicator

                // Present error to user
                console.log(event.error);
            }
        });

   }
}

2
これは素晴らしい!とても包括的です!Angular 7で完璧に動作しました
MaylorTaylor

1
通常、プリロード戦略を使用すると、ナビゲーション自体にほとんど時間がかかりません。使いやすさの面では、もしあれば、バックエンドのhttpリクエストでのみ読み込みインジケーターを使用します。
Phil

5
では、コンストラクタ、あなたは<この>を使用しないでください、あなたのケースはngOnInitためです。
Sergio Reis

1
完璧、どうすればURLの正確なparam.idを取得できますか?
ShibinRagh

2
ソリューションはコンポーネントに限定されず、アプリ全体に広がり、リソースを消費します
Md。Rafee

54

Angular 7、必要に応じsubscriberouter

import { Router, NavigationEnd } from '@angular/router';

import { filter } from 'rxjs/operators';

constructor(
  private router: Router
) {
  router.events.pipe(
    filter(event => event instanceof NavigationEnd)  
  ).subscribe((event: NavigationEnd) => {
    console.log(event.url);
  });
}

2
リダイレクトイベントはキャプチャされません
Anandhu Ajayakumar

40

Angular 4.x以降:

これは、以下のようにActivatedRouteクラスのurlプロパティを使用して実現できます。

this.activatedRoute.url.subscribe(url =>{
     console.log(url);
});

注: プロバイダーをangular/routerパッケージからインポートして注入する必要があること

import { ActivatedRoute } from '@angular/router`

そして

constructor(private activatedRoute : ActivatedRoute){  }

18

ルーター3.0.0-beta.2は

this.router.events.subscribe(path => {
  console.log('path = ', path);
});

それは現在のパスで機​​能しますが、以前のパスはどうですか?
tatsu

16

角度6およびRxJS6の場合:

import { filter, debounceTime } from 'rxjs/operators';

 this.router.events.pipe(
      filter((event) => event instanceof NavigationEnd),
      debounceTime(40000)
    ).subscribe(
      x => {
      console.log('val',x);
      this.router.navigate(['/']); /*Redirect to Home*/
}
)

3
ルーターのインポートに失敗しましたimport {Router, NavigationEnd} from "@angular/router"
Damir Beylkhanov 2018

15

ここでの答えは正しいですrouter-deprecated。最新バージョンの場合router

this.router.changes.forEach(() => {
    // Do whatever in here
});

または

this.router.changes.subscribe(() => {
     // Do whatever in here
});

2つの違いを確認するには、このSOの質問を確認してください。

編集する

最新の場合は、次のことを行う必要があります。

this.router.events.subscribe(event: Event => {
    // Handle route change
});

以前のルートと現在のルートのデータはありますか?
akn

router(私はまだ私の答えを更新していない)を再び更新されているので、私はそれが最新のためであるかどうかはわかりません。以下のためにrouter私が書いた、あなたはできませんでした。@akn
Dehli

この回答の背景を教えてください。他のソリューションでどのラインを置き換えますか?
Gerard Simpson

12

Angular 8では次のようにする必要があります this.router.events.subscribe((event: Event) => {})

例:

import { Component } from '@angular/core'; 
import { Router, Event } from '@angular/router';
import { NavigationStart, NavigationError, NavigationEnd } from '@angular/router';

@Component({
    selector: 'app-root',
    template: `<router-outlet></router-outlet>`
})
export class AppComponent {

    constructor(private router: Router) {
        //Router subscriber
        this.router.events.subscribe((event: Event) => {
            if (event instanceof NavigationStart) {
                //do something on start activity
            }

            if (event instanceof NavigationError) {
                // Handle error
                console.error(event.error);
            }

            if (event instanceof NavigationEnd) {
                //do something on end activity
            }
        });
   }
}

10

コンポーネントでは、これを試してみてください:

import {NavigationEnd, NavigationStart, Router} from '@angular/router';

constructor(private router: Router) {
router.events.subscribe(
        (event) => {
            if (event instanceof NavigationStart)
                // start loading pages
            if (event instanceof NavigationEnd) {
                // end of loading paegs
            }
        });
}

8

ルート変更イベントを次の方法でキャプチャします...

import { Component, OnInit, Output, ViewChild } from "@angular/core";
import { Router, NavigationStart, NavigationEnd, Event as NavigationEvent } from '@angular/router';

@Component({
    selector: "my-app",
    templateUrl: "app/app.component.html",
    styleUrls: ["app/app.component.css"]
})
export class AppComponent {

    constructor(private cacheComponentObj: CacheComponent,
        private router: Router) {

        /*  Route event types
            NavigationEnd
            NavigationCancel
            NavigationError
            RoutesRecognized
        */
        router.events.forEach((event: NavigationEvent) => {

            //Before Navigation
            if (event instanceof NavigationStart) {
                switch (event.url) {
                case "/app/home":
                {
                    //Do Work
                    break;
                }
                case "/app/About":
                {
                    //Do Work
                    break;
                }
                }
            }

            //After Navigation
            if (event instanceof NavigationEnd) {
                switch (event.url) {
                case "/app/home":
                {
                    //Do Work
                    break;
                }
                case "/app/About":
                {
                    //Do Work
                    break;
                }
                }
            }
        });
    }
}

完璧、どうすればURLの正確なparam.idを取得できますか?
ShibinRagh

6

ロケーションは機能します...

import {Component, OnInit} from '@angular/core';
import {Location} from '@angular/common';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent implements OnInit {

    constructor(private location: Location) {
        this.location.onUrlChange(x => this.urlChange(x));
    }

    ngOnInit(): void {}

    urlChange(x) {
        console.log(x);
    }
}

いい答えだ。私の場合は問題ありません。ありがとう
Umar Tariq

4

上記のほとんどの解決策は正しいですが、問題が発生しています。これは複数回の「ナビゲーション放出」イベントを発生させます。ルートを変更すると、このイベントがトリガーされます。Angular 6の完全なソリューションです。

import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/filter';    

export class FooComponent implements OnInit, OnDestroy {
   private _routerSub = Subscription.EMPTY;
   constructor(private router: Router){}

   ngOnInit(){
     this._routerSub = this.router.events
      .filter(event => event instanceof NavigationEnd)
      .subscribe((value) => {
         //do something with the value
     });
  }

  ngOnDestroy(){
   this._routerSub.unsubscribe();
  }
} 

3

@Ludohenの回答は素晴らしいですが、使用したくない場合instanceofは以下を使用してください

this.router.events.subscribe(event => {
  if(event.constructor.name === "NavigationStart") {
    // do something...
  }
});

この方法を使用すると、現在のイベント名を文字列として確認でき、イベントが発生した場合は、関数に予定していたことを実行できます。


3
typescript safeを使用しないのはなぜですか?
Pascal

@Pascalなぜ嫌いなの?そして、Eventタイプは、私はそれを使用しなかった理由だアトムでエラーの原因となっている
ハレドアル・アンサリ

2
@Pascalいいえ、ルーターイベントはブラウザイベントと同じではないため、Angularの問題であり、そのため、Eventタイプは機能しません。彼らはこのイベントのために新しいインターフェースを作成する必要があります、私は最初から言ったはずですが、不当な反対票は役に立たなかった:)
Khaled Al-Ansari

5
縮小化は本番用コードで実行されるinstanceOfため、サンプルを本番用コードでも機能させるために使用する必要があります。if(event instanceOf NavigationStart) {
ミラノジャリック2017年

1
する必要がありますif(event instanceof NavigationStart)
Ketan

1

angular5アプリケーションを使用していますが、同じ問題に直面しています。Angularドキュメントを確認すると、ルーターイベントを処理するための最適なソリューションが提供されます。次のドキュメントを確認してください。

ナビゲーションが正常に終了したときにトリガーされるイベントを表します

これの使い方は?

import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRouteSnapshot, NavigationEnd } from '@angular/router';
@Component({
    selector: 'app-navbar',
    templateUrl: './navbar.component.html',
    styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
    constructor(private router: Router) { }
    ngOnInit(): void {
        //calls this method when navigation ends
        this.router.events.subscribe(event => {
            if (event instanceof NavigationEnd) {
                //calls this stuff when navigation ends
                console.log("Event generated");
            }
        });
    }
}

いつこれを使うのですか?

私の場合、アプリケーションはusers、Adminsなどのすべてのユーザーの共通ダッシュボードを共有していますが、ユーザータイプごとにいくつかのナビゲーションバーオプションを表示または非表示にする必要があります。

そのため、URLが変更されるたびに、応答に従ってログインユーザー情報を返すサービスメソッドを呼び出す必要があります。


0

以下の種類の作品は、あなたのためにトリッキーなことをするかもしれません。

// in constructor of your app.ts with router and auth services injected
router.subscribe(path => {
    if (!authService.isAuthorised(path)) //whatever your auth service needs
        router.navigate(['/Login']);
    });

残念ながら、これはルーティングプロセスの後半でリダイレクトされます。onActivate()元のターゲット・コンポーネントのは、リダイレクト前に呼び出されます。

@CanActivateターゲットコンポーネントで使用できるデコレータがありますが、これはa)一元化されておらず、b)インジェクトされたサービスの恩恵を受けていません。

それがコミットされる前に、誰かがルートを中央で承認するより良い方法を提案することができれば素晴らしいでしょう。もっと良い方法があるに違いない。

これは私の現在のコードです(ルートの変更をリッスンするにはどうすればよいですか?):

import {Component, View, bootstrap, bind, provide} from 'angular2/angular2';
import {ROUTER_BINDINGS, RouterOutlet, RouteConfig, RouterLink, ROUTER_PROVIDERS, APP_BASE_HREF} from 'angular2/router';    
import {Location, LocationStrategy, HashLocationStrategy} from 'angular2/router';

import { Todo } from './components/todo/todo';
import { About } from './components/about/about';

@Component({
    selector: 'app'
})

@View({
    template: `
        <div class="container">
            <nav>
                <ul>
                    <li><a [router-link]="['/Home']">Todo</a></li>
                    <li><a [router-link]="['/About']">About</a></li>
                </ul>
            </nav>
            <router-outlet></router-outlet>
        </div>
    `,
    directives: [RouterOutlet, RouterLink]
})

@RouteConfig([
    { path: '/', redirectTo: '/home' },
    { path: '/home', component: Todo, as: 'Home' },
    { path: '/about', component: About, as: 'About' }
])

class AppComponent {    
    constructor(location: Location){
        location.go('/');
    }    
}    
bootstrap(AppComponent, [ROUTER_PROVIDERS, provide(APP_BASE_HREF, {useValue: '/'})]);

私は、人々がrouterOutletを拡張して、一方通行の認証コードを追加するのを見てきました。gitHubでそれについての話がありますが、まだ結論はありません。Auth0の方法は次のとおり
Dennis Smolek

ご回答ありがとうございます。angular 2のauthServiceを学ぶための良いビデオを知っていますか?
AngularM

0

RC 5以降はこのようにしています

this.router.events
  .map( event => event instanceof NavigationStart )
  .subscribe( () => {
    // TODO
  } );

0

次のようにAppRoutingModuleに変更を加えるだけです

@NgModule({
imports: [RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled' })],
  exports: [RouterModule]
})

0

Angular 8.現在のルートがベースルートであるかどうかを確認します。

  baseroute: boolean;
  constructor(
    private router: Router,
  ) {
    router.events.subscribe((val: any) => {
      if (val.url == "/") {
        this.baseroute = true;
      } else {
        this.baseroute = false;
      }
    });
  }

0

私はこのようなものを書きます:

ngOnInit() {
this.routed = this.router.events.map( event => event instanceof NavigationStart )
  .subscribe(() => {
  } );
}

ngOnDestroy() {
this.routed.unsubscribe();
}

-3

Angular 8. *の簡単な答え

constructor(private route:ActivatedRoute) {
  console.log(route);
}

1
これはインスタンス化時にのみ実行されるのではないですか?それは:一度だけです!?これは解決策ではありません。
Satria、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.