diff --git a/modules/@angular/router/src/router.ts b/modules/@angular/router/src/router.ts index 058b375e00..782ebf44e2 100644 --- a/modules/@angular/router/src/router.ts +++ b/modules/@angular/router/src/router.ts @@ -288,7 +288,14 @@ export class Router { private setUpLocationChangeListener(): void { this.locationSubscription = this.location.subscribe((change) => { - return this.scheduleNavigation(this.urlSerializer.parse(change['url']), change['pop']); + const tree = this.urlSerializer.parse(change['url']); + // we fire multiple events for a single URL change + // we should navigate only once + if (this.currentUrlTree.toString() !== tree.toString()) { + return this.scheduleNavigation(tree, change['pop']); + } else { + return null; + } }); } diff --git a/modules/@angular/router/test/router.spec.ts b/modules/@angular/router/test/router.spec.ts index 18d6696c0a..f456142c71 100644 --- a/modules/@angular/router/test/router.spec.ts +++ b/modules/@angular/router/test/router.spec.ts @@ -111,13 +111,27 @@ describe('Integration', () => { children: [{path: 'user/:name', component: UserCmp}] }]); + const recordedEvents: any = []; + router.events.forEach(e => recordedEvents.push(e)); + router.navigateByUrl('/team/22/user/victor'); advance(fixture); (location).simulateHashChange('/team/22/user/fedor'); advance(fixture); - expect(fixture.debugElement.nativeElement).toHaveText('team 22 [ user fedor, right: ]'); + (location).simulateUrlPop('/team/22/user/fedor'); + advance(fixture); + + expect(fixture.debugElement.nativeElement).toHaveText('team 22 { user fedor, right: }'); + + expectEvents(recordedEvents, [ + [NavigationStart, '/team/22/user/victor'], [RoutesRecognized, '/team/22/user/victor'], + [NavigationEnd, '/team/22/user/victor'], + + [NavigationStart, '/team/22/user/fedor'], [RoutesRecognized, '/team/22/user/fedor'], + [NavigationEnd, '/team/22/user/fedor'] + ]); }))); it('should update the location when the matched route does not change',