Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(router): Remove deprecated relativeLinkResolution #47623

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 1 addition & 5 deletions goldens/public-api/router/index.md
Expand Up @@ -283,14 +283,12 @@ export const enum EventType {
}

// @public
export interface ExtraOptions extends InMemoryScrollingOptions, RouterConfigOptions {
export interface ExtraOptions extends InMemoryScrollingOptions, RouterConfigOptions, InternalExtraOptions {
AndrewKushnir marked this conversation as resolved.
Show resolved Hide resolved
enableTracing?: boolean;
errorHandler?: ErrorHandler;
initialNavigation?: InitialNavigation;
malformedUriErrorHandler?: (error: URIError, urlSerializer: UrlSerializer, url: string) => UrlTree;
preloadingStrategy?: any;
// @deprecated
relativeLinkResolution?: 'legacy' | 'corrected';
scrollOffset?: [number, number] | (() => [number, number]);
useHash?: boolean;
}
Expand Down Expand Up @@ -648,8 +646,6 @@ export class Router {
onSameUrlNavigation: 'reload' | 'ignore';
paramsInheritanceStrategy: 'emptyOnly' | 'always';
parseUrl(url: string): UrlTree;
// @deprecated
relativeLinkResolution: 'legacy' | 'corrected';
resetConfig(config: Routes): void;
routeReuseStrategy: RouteReuseStrategy;
readonly routerState: RouterState;
Expand Down
2 changes: 2 additions & 0 deletions packages/router/src/patchable_relative_link_resolution.ts
Expand Up @@ -11,3 +11,5 @@
*/
export function assignRelativeLinkResolution(
router: {relativeLinkResolution: 'legacy'|'corrected'}): void {}

export interface InternalExtraOptions {}
11 changes: 3 additions & 8 deletions packages/router/src/router.ts
Expand Up @@ -310,10 +310,6 @@ export function assignExtraOptionsToRouter(opts: ExtraOptions, router: Router):
router.paramsInheritanceStrategy = opts.paramsInheritanceStrategy;
}

if (opts.relativeLinkResolution) {
router.relativeLinkResolution = opts.relativeLinkResolution;
}

if (opts.urlUpdateStrategy) {
router.urlUpdateStrategy = opts.urlUpdateStrategy;
}
Expand Down Expand Up @@ -531,10 +527,9 @@ export class Router {
urlUpdateStrategy: 'deferred'|'eager' = 'deferred';

/**
* Enables a bug fix that corrects relative link resolution in components with empty paths.
* @see `RouterModule`
*
* @deprecated
* TODO(atscott): Remove all references to relativeLinkResolution when internal cleanup is
* finished.
* @internal
*/
relativeLinkResolution: 'legacy'|'corrected' = 'corrected';

Expand Down
40 changes: 3 additions & 37 deletions packages/router/src/router_config.ts
Expand Up @@ -8,6 +8,7 @@

import {InjectionToken} from '@angular/core';

import {InternalExtraOptions} from './patchable_relative_link_resolution';
import {UrlSerializer, UrlTree} from './url_tree';

const NG_DEV_MODE = typeof ngDevMode === 'undefined' || !!ngDevMode;
Expand Down Expand Up @@ -172,7 +173,8 @@ export interface InMemoryScrollingOptions {
*
* @publicApi
*/
export interface ExtraOptions extends InMemoryScrollingOptions, RouterConfigOptions {
export interface ExtraOptions extends InMemoryScrollingOptions, RouterConfigOptions,
InternalExtraOptions {
/**
* When true, log all internal navigation events to the console.
* Use for debugging.
Expand Down Expand Up @@ -234,42 +236,6 @@ export interface ExtraOptions extends InMemoryScrollingOptions, RouterConfigOpti
* */
malformedUriErrorHandler?:
(error: URIError, urlSerializer: UrlSerializer, url: string) => UrlTree;

/**
* Enables a bug fix that corrects relative link resolution in components with empty paths.
* Example:
*
* ```
* const routes = [
* {
* path: '',
* component: ContainerComponent,
* children: [
* { path: 'a', component: AComponent },
* { path: 'b', component: BComponent },
* ]
* }
* ];
* ```
*
* From the `ContainerComponent`, you should be able to navigate to `AComponent` using
* the following `routerLink`, but it will not work if `relativeLinkResolution` is set
* to `'legacy'`:
*
* `<a [routerLink]="['./a']">Link to A</a>`
*
* However, this will work:
*
* `<a [routerLink]="['../a']">Link to A</a>`
*
* In other words, you're required to use `../` rather than `./` when the relative link
* resolution is set to `'legacy'`.
*
* The default in v11 is `corrected`.
*
* @deprecated
*/
relativeLinkResolution?: 'legacy'|'corrected';
}

/**
Expand Down
111 changes: 32 additions & 79 deletions packages/router/test/integration.spec.ts
Expand Up @@ -83,45 +83,22 @@ describe('Integration', () => {
]);
})));

describe('relativeLinkResolution', () => {
beforeEach(inject([Router], (router: Router) => {
router.resetConfig([{
path: 'foo',
children: [{path: 'bar', children: [{path: '', component: RelativeLinkCmp}]}]
}]);
}));

it('should not ignore empty paths in legacy mode',
fakeAsync(inject([Router], (router: Router) => {
const warnSpy = spyOn(console, 'warn');
router.relativeLinkResolution = 'legacy';

const fixture = createRoot(router, RootCmp);

router.navigateByUrl('/foo/bar');
advance(fixture);

const link = fixture.nativeElement.querySelector('a');
expect(link.getAttribute('href')).toEqual('/foo/bar/simple');
expect(warnSpy.calls.first().args[0])
.toContain('/foo/bar/simple will change to /foo/simple');
expect(warnSpy.calls.first().args[0])
.toContain('relativeLinkResolution: \'legacy\' is deprecated');
})));

it('should ignore empty paths in corrected mode',
fakeAsync(inject([Router], (router: Router) => {
router.relativeLinkResolution = 'corrected';
it('should ignore empty paths in relative links',
fakeAsync(inject([Router], (router: Router) => {
router.resetConfig([{
path: 'foo',
children: [{path: 'bar', children: [{path: '', component: RelativeLinkCmp}]}]
}]);

const fixture = createRoot(router, RootCmp);
const fixture = createRoot(router, RootCmp);

router.navigateByUrl('/foo/bar');
advance(fixture);
router.navigateByUrl('/foo/bar');
advance(fixture);

const link = fixture.nativeElement.querySelector('a');
expect(link.getAttribute('href')).toEqual('/foo/simple');
})));
});
const link = fixture.nativeElement.querySelector('a');
expect(link.getAttribute('href')).toEqual('/foo/simple');
})));

it('should set the restoredState to null when executing imperative navigations',
fakeAsync(inject([Router], (router: Router) => {
Expand Down Expand Up @@ -6474,55 +6451,31 @@ describe('Integration', () => {
expect(relativeLinkCmp.buttonLink.urlTree.toString()).toEqual('/root/childRoot');
}));

describe('relativeLinkResolution', () => {
@Component({selector: 'link-cmp', template: `<a [routerLink]="['../simple']">link</a>`})
class RelativeLinkCmp {
}

@NgModule({
declarations: [RelativeLinkCmp],
imports: [RouterModule.forChild([
{path: 'foo/bar', children: [{path: '', component: RelativeLinkCmp}]},
])]
})
class LazyLoadedModule {
}

it('should not ignore empty path when in legacy mode',
fakeAsync(inject([Router], (router: Router) => {
const warnSpy = spyOn(console, 'warn');
router.relativeLinkResolution = 'legacy';

const fixture = createRoot(router, RootCmp);

router.resetConfig([{path: 'lazy', loadChildren: () => LazyLoadedModule}]);

router.navigateByUrl('/lazy/foo/bar');
advance(fixture);

const link = fixture.nativeElement.querySelector('a');
expect(link.getAttribute('href')).toEqual('/lazy/foo/bar/simple');
expect(warnSpy.calls.first().args[0])
.toContain('/lazy/foo/bar/simple will change to /lazy/foo/simple');
expect(warnSpy.calls.first().args[0])
.toContain('relativeLinkResolution: \'legacy\' is deprecated');
})));
it('should ignore empty path for relative links',
fakeAsync(inject([Router], (router: Router) => {
@Component({selector: 'link-cmp', template: `<a [routerLink]="['../simple']">link</a>`})
class RelativeLinkCmp {
}

it('should ignore empty path when in corrected mode',
fakeAsync(inject([Router], (router: Router) => {
router.relativeLinkResolution = 'corrected';
@NgModule({
declarations: [RelativeLinkCmp],
imports: [RouterModule.forChild([
{path: 'foo/bar', children: [{path: '', component: RelativeLinkCmp}]},
])]
})
class LazyLoadedModule {
}

const fixture = createRoot(router, RootCmp);
const fixture = createRoot(router, RootCmp);

router.resetConfig([{path: 'lazy', loadChildren: () => LazyLoadedModule}]);
router.resetConfig([{path: 'lazy', loadChildren: () => LazyLoadedModule}]);

router.navigateByUrl('/lazy/foo/bar');
advance(fixture);
router.navigateByUrl('/lazy/foo/bar');
advance(fixture);

const link = fixture.nativeElement.querySelector('a');
expect(link.getAttribute('href')).toEqual('/lazy/foo/simple');
})));
});
const link = fixture.nativeElement.querySelector('a');
expect(link.getAttribute('href')).toEqual('/lazy/foo/simple');
})));
});

describe('Custom Route Reuse Strategy', () => {
Expand Down