fix(router): should pass new data to Observable when query params change (#15387)

Fixes #15290
This commit is contained in:
Dzmitry Shylovich 2017-03-23 20:43:14 +03:00 committed by Victor Berchet
parent 376088da70
commit 08f2f08d74
2 changed files with 85 additions and 74 deletions

View File

@ -381,7 +381,7 @@ export function advanceActivatedRoute(route: ActivatedRoute): void {
if (!shallowEqualArrays(currentSnapshot.url, route._futureSnapshot.url)) { if (!shallowEqualArrays(currentSnapshot.url, route._futureSnapshot.url)) {
(<any>route.url).next(route._futureSnapshot.url); (<any>route.url).next(route._futureSnapshot.url);
} }
if (!equalParamsAndUrlSegments(currentSnapshot, route._futureSnapshot)) { if (!shallowEqual(currentSnapshot.data, route._futureSnapshot.data)) {
(<any>route.data).next(route._futureSnapshot.data); (<any>route.data).next(route._futureSnapshot.data);
} }
} else { } else {
@ -400,4 +400,4 @@ export function equalParamsAndUrlSegments(
return equalUrlParams && !parentsMismatch && return equalUrlParams && !parentsMismatch &&
(!a.parent || equalParamsAndUrlSegments(a.parent, b.parent)); (!a.parent || equalParamsAndUrlSegments(a.parent, b.parent));
} }

View File

@ -14,7 +14,7 @@ import {expect} from '@angular/platform-browser/testing/src/matchers';
import {Observable} from 'rxjs/Observable'; import {Observable} from 'rxjs/Observable';
import {map} from 'rxjs/operator/map'; import {map} from 'rxjs/operator/map';
import {ActivatedRoute, ActivatedRouteSnapshot, CanActivate, CanDeactivate, DetachedRouteHandle, Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, PRIMARY_OUTLET, ParamMap, Params, PreloadAllModules, PreloadingStrategy, Resolve, RouteConfigLoadEnd, RouteConfigLoadStart, RouteReuseStrategy, Router, RouterModule, RouterStateSnapshot, RoutesRecognized, UrlHandlingStrategy, UrlSegmentGroup, UrlTree} from '../index'; import {ActivatedRoute, ActivatedRouteSnapshot, CanActivate, CanDeactivate, DetachedRouteHandle, Event, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, PRIMARY_OUTLET, ParamMap, Params, PreloadAllModules, PreloadingStrategy, Resolve, RouteConfigLoadEnd, RouteConfigLoadStart, RouteReuseStrategy, Router, RouterModule, RouterStateSnapshot, RoutesRecognized, RunGuardsAndResolvers, UrlHandlingStrategy, UrlSegmentGroup, UrlTree} from '../index';
import {RouterPreloader} from '../src/router_preloader'; import {RouterPreloader} from '../src/router_preloader';
import {forEach} from '../src/utils/collection'; import {forEach} from '../src/utils/collection';
import {RouterTestingModule, SpyNgModuleFactoryLoader} from '../testing'; import {RouterTestingModule, SpyNgModuleFactoryLoader} from '../testing';
@ -897,12 +897,8 @@ describe('Integration', () => {
router.navigateByUrl('/parent/2'); router.navigateByUrl('/parent/2');
advance(fixture); advance(fixture);
expect(primaryRecorded).toEqual([ expect(primaryRecorded).toEqual([{one: 1, three: 3, two: 2, four: 4}]);
{one: 1, three: 3, two: 2, four: 4}, {one: 1, three: 3, two: 2, four: 4} expect(rightRecorded).toEqual([{one: 1, five: 5, two: 2, six: 6}]);
]);
expect(rightRecorded).toEqual([
{one: 1, five: 5, two: 2, six: 6}, {one: 1, five: 5, two: 2, six: 6}
]);
}))); })));
it('should handle errors', fakeAsync(inject([Router], (router: Router) => { it('should handle errors', fakeAsync(inject([Router], (router: Router) => {
@ -1529,120 +1525,135 @@ describe('Integration', () => {
}); });
describe('runGuardsAndResolvers', () => { describe('runGuardsAndResolvers', () => {
let count = 0; let guardRunCount = 0;
let resolverRunCount = 0;
beforeEach(() => { beforeEach(() => {
count = 0; guardRunCount = 0;
resolverRunCount = 0;
TestBed.configureTestingModule({ TestBed.configureTestingModule({
providers: [{ providers: [
provide: 'loggingCanActivate', {
useValue: (a: any, b: any) => { provide: 'guard',
count++; useValue: () => {
return true; guardRunCount++;
} return true;
}] }
},
{provide: 'resolver', useValue: () => resolverRunCount++}
]
}); });
}); });
it('should rerun guards when params change', function configureRouter(router: Router, runGuardsAndResolvers: RunGuardsAndResolvers):
fakeAsync(inject([Router, Location], (router: Router, location: Location) => { ComponentFixture<RootCmpWithTwoOutlets> {
const fixture = createRoot(router, RootCmpWithTwoOutlets); const fixture = createRoot(router, RootCmpWithTwoOutlets);
router.resetConfig([ router.resetConfig([
{ {
path: 'a', path: 'a',
runGuardsAndResolvers: 'paramsChange', runGuardsAndResolvers,
component: SimpleCmp, component: RouteCmp,
canActivate: ['loggingCanActivate'] canActivate: ['guard'],
}, resolve: {data: 'resolver'}
{path: 'b', component: SimpleCmp, outlet: 'right'} },
]); {path: 'b', component: SimpleCmp, outlet: 'right'}
]);
router.navigateByUrl('/a'); router.navigateByUrl('/a');
advance(fixture); advance(fixture);
expect(count).toEqual(1); return fixture;
}
it('should rerun guards and resolvers when params change',
fakeAsync(inject([Router], (router: Router) => {
const fixture = configureRouter(router, 'paramsChange');
const cmp: RouteCmp = fixture.debugElement.children[1].componentInstance;
const recordedData: any[] = [];
cmp.route.data.subscribe((data: any) => recordedData.push(data));
expect(guardRunCount).toEqual(1);
expect(recordedData).toEqual([{data: 0}]);
router.navigateByUrl('/a;p=1'); router.navigateByUrl('/a;p=1');
advance(fixture); advance(fixture);
expect(count).toEqual(2); expect(guardRunCount).toEqual(2);
expect(recordedData).toEqual([{data: 0}, {data: 1}]);
router.navigateByUrl('/a;p=2'); router.navigateByUrl('/a;p=2');
advance(fixture); advance(fixture);
expect(count).toEqual(3); expect(guardRunCount).toEqual(3);
expect(recordedData).toEqual([{data: 0}, {data: 1}, {data: 2}]);
router.navigateByUrl('/a;p=2?q=1'); router.navigateByUrl('/a;p=2?q=1');
advance(fixture); advance(fixture);
expect(count).toEqual(3); expect(guardRunCount).toEqual(3);
expect(recordedData).toEqual([{data: 0}, {data: 1}, {data: 2}]);
}))); })));
it('should rerun guards when query params change', it('should rerun guards and resolvers when query params change',
fakeAsync(inject([Router, Location], (router: Router, location: Location) => { fakeAsync(inject([Router], (router: Router) => {
const fixture = createRoot(router, RootCmpWithTwoOutlets); const fixture = configureRouter(router, 'paramsOrQueryParamsChange');
router.resetConfig([ const cmp: RouteCmp = fixture.debugElement.children[1].componentInstance;
{ const recordedData: any[] = [];
path: 'a', cmp.route.data.subscribe((data: any) => recordedData.push(data));
runGuardsAndResolvers: 'paramsOrQueryParamsChange',
component: SimpleCmp,
canActivate: ['loggingCanActivate']
},
{path: 'b', component: SimpleCmp, outlet: 'right'}
]);
router.navigateByUrl('/a'); expect(guardRunCount).toEqual(1);
advance(fixture); expect(recordedData).toEqual([{data: 0}]);
expect(count).toEqual(1);
router.navigateByUrl('/a;p=1'); router.navigateByUrl('/a;p=1');
advance(fixture); advance(fixture);
expect(count).toEqual(2); expect(guardRunCount).toEqual(2);
expect(recordedData).toEqual([{data: 0}, {data: 1}]);
router.navigateByUrl('/a;p=2'); router.navigateByUrl('/a;p=2');
advance(fixture); advance(fixture);
expect(count).toEqual(3); expect(guardRunCount).toEqual(3);
expect(recordedData).toEqual([{data: 0}, {data: 1}, {data: 2}]);
router.navigateByUrl('/a;p=2?q=1'); router.navigateByUrl('/a;p=2?q=1');
advance(fixture); advance(fixture);
expect(count).toEqual(4); expect(guardRunCount).toEqual(4);
expect(recordedData).toEqual([{data: 0}, {data: 1}, {data: 2}, {data: 3}]);
router.navigateByUrl('/a;p=2(right:b)?q=1'); router.navigateByUrl('/a;p=2(right:b)?q=1');
advance(fixture); advance(fixture);
expect(count).toEqual(4); expect(guardRunCount).toEqual(4);
expect(recordedData).toEqual([{data: 0}, {data: 1}, {data: 2}, {data: 3}]);
}))); })));
it('should always rerun guards', it('should always rerun guards and resolvers',
fakeAsync(inject([Router, Location], (router: Router, location: Location) => { fakeAsync(inject([Router], (router: Router) => {
const fixture = createRoot(router, RootCmpWithTwoOutlets); const fixture = configureRouter(router, 'always');
router.resetConfig([ const cmp: RouteCmp = fixture.debugElement.children[1].componentInstance;
{ const recordedData: any[] = [];
path: 'a', cmp.route.data.subscribe((data: any) => recordedData.push(data));
runGuardsAndResolvers: 'always',
component: SimpleCmp,
canActivate: ['loggingCanActivate']
},
{path: 'b', component: SimpleCmp, outlet: 'right'}
]);
router.navigateByUrl('/a'); expect(guardRunCount).toEqual(1);
advance(fixture); expect(recordedData).toEqual([{data: 0}]);
expect(count).toEqual(1);
router.navigateByUrl('/a;p=1'); router.navigateByUrl('/a;p=1');
advance(fixture); advance(fixture);
expect(count).toEqual(2); expect(guardRunCount).toEqual(2);
expect(recordedData).toEqual([{data: 0}, {data: 1}]);
router.navigateByUrl('/a;p=2'); router.navigateByUrl('/a;p=2');
advance(fixture); advance(fixture);
expect(count).toEqual(3); expect(guardRunCount).toEqual(3);
expect(recordedData).toEqual([{data: 0}, {data: 1}, {data: 2}]);
router.navigateByUrl('/a;p=2?q=1'); router.navigateByUrl('/a;p=2?q=1');
advance(fixture); advance(fixture);
expect(count).toEqual(4); expect(guardRunCount).toEqual(4);
expect(recordedData).toEqual([{data: 0}, {data: 1}, {data: 2}, {data: 3}]);
router.navigateByUrl('/a;p=2(right:b)?q=1'); router.navigateByUrl('/a;p=2(right:b)?q=1');
advance(fixture); advance(fixture);
expect(count).toEqual(5); expect(guardRunCount).toEqual(5);
expect(recordedData).toEqual([{data: 0}, {data: 1}, {data: 2}, {data: 3}, {data: 4}]);
}))); })));
}); });