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 doc

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이 성공적으로 변경 되었기 때문입니다. 세 가지 상태는 'NavigationStart', 'NavigationEnd'및 'RoutesRecognized'입니다.
RicardoGonzales

10
RxJS filter연산자로 이벤트를 쉽게 필터링 할 수 있습니다 . router.events.pipe(filter(e => e instanceof NavigationEnd).subscribe((e) => { ... }
Simon_Weaver

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'를 사용합니다. 그리고 'event : Event'는 괄호 안에 있어야합니다. 이 강력한 새 기능에 감사드립니다! 나는 그것을 좋아한다
Maxim

2
현재 버전에서 컴파일 오류가 발생합니다Argument of type '(event: Event) => void' is not assignable to parameter of type
Rudi Strydom

1
@RudiStrydom & Günter Zöchbauer- Argument of type '(event: Event) => void' is not assignable to parameter of type오류는 필터 스 니펫에서 NavigationEvent 대신 Event 유형의 객체를 구독하고 있기 때문입니다.
Bonnici

1
두 번째 샘플은 이벤트 대신 NavigationEvent 여야합니다. 또한 @ angular / router에서 "Event as NavigationEvent"를 가져 오는 것을 잊지
Mick

1
수입에 대한 힌트는이 오류를 해결하고자하는 사람을위한 것입니다 :)
Mick

91

들어 각도 일곱 사람이 같이 작성해야합니다 :

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
대단해! 매우 포괄적! 각도 7. 완벽하게 작동
MaylorTaylor

1
사전로드 전략을 사용하는 경우 일반적으로 탐색 자체에는 시간이 거의 없습니다. 유용성 측면에서 백엔드 http 요청에 대해서만 로딩 표시기를 사용합니다.
Phil

5
에서 생성자 , 당신은 <이>, 귀하의 경우는 ngOnInit입니다 사용할 수 없습니다.
세르지오 Reis

1
완벽, 어떻게 정확한 param.id url을 얻을 수 있습니까?
ShibinRagh

2
솔루션은 구성 요소에 국한되지 않고 앱 전체에 퍼져 리소스를 소비합니다
Md. Rafee

54

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

각도 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

15

여기에 대한 답변이 옳습니다 router-deprecated. 최신 버전 router:

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

또는

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

이 둘의 차이점을 확인하려면 이 SO 질문을 확인하십시오 .

편집하다

최신의 경우 다음을 수행해야합니다.

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

이전 및 현재 경로의 데이터를 제공합니까?
akn

router다시 업데이트되었습니다 (아직 답변을 업데이트하지 않았습니다). 최신 업데이트 방법이 확실하지 않습니다. 를 들어 router내가 쓴, 당신은 할 수 없습니다. @akn
Dehli

이 답변에 대한 컨텍스트를 제공해 주시겠습니까? 다른 솔루션에서 어떤 라인을 귀하의 것으로 대체합니까?
제라드 심슨

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

완벽, 어떻게 정확한 param.id url을 얻을 수 있습니까?
ShibinRagh 2014 년

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

위의 대부분의 솔루션은 정확하지만 문제가 발생했습니다 .'Navigation emit '이벤트가 여러 번 발생합니다. 경로를 변경하면이 이벤트가 트리거됩니다. 따라서 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
왜 타이프 스크립트 안전을 사용하지 않습니까?
Pascal

@ 파스칼 왜 싫어? 그리고 Event형은 내가 그것을 사용하지 않은 이유 아톰의 오류의 원인이되는
칼레드 알 - 안사리

2
@Pascal 아니요 라우터 이벤트가 브라우저 이벤트와 같지 않기 때문에 Angular 문제입니다. 그래서 이벤트 유형이 작동하지 않습니다! 그들은이 이벤트를위한 새로운 인터페이스를 만들어야합니다. 처음부터 말했지만 불합리한 다운 투표는 도움이되지 않았습니다.)
Khaled Al-Ansari

5
축소는 프로덕션 코드에서 수행 instanceOf되므로 예제를 프로덕션 코드에서도 작동하도록 사용해야 합니다. if(event instanceOf NavigationStart) {
밀라노 Jaric

1
이어야한다if(event instanceof NavigationStart)
케탄에게

1

angular5 응용 프로그램으로 작업 중이며 같은 문제에 직면하고 있습니다. Angular Documentation을 살펴보면 라우터 이벤트를 처리하는 최상의 솔루션을 제공합니다. 다음 설명서를 확인하십시오.

탐색이 성공적으로 종료 될 때 트리거되는 이벤트를 나타냅니다.

이것을 사용하는 방법?

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의 방법은 없습니다 : auth0.com/blog/2015/05/14/...은
데니스 Smolek

당신의 응답을 주셔서 감사합니다. 각도 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

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