Skip to content

Upgrading @angular/router 14 to 15

Breaking14.3.0 → 15.2.10Breaking14Security3Platform5Deprecated12New36Changed8Fixed128Other6

BreakingUpgrade verdict

14 breaking changes and 5 platform requirement changes and 3 security fixes.

  • Animation keyframe names inside components get a component-specific prefix, so any code that looked them up by their old names will break.
  • The `enableIvy` compiler option is gone because Ivy is now the only rendering engine.
  • Localization tooling drops the `canParse` method in favor of `analyze`, and the `hint` parameter of `parse` is now required.
  • Routed components are created later, when change detection runs, which can affect tests or code relying on exact timing.
Top 5 of 31 that need code or config changes

Node.js requirement changed in 15.0.0-next.6: ^14.15.0 || >=16.10.0 → ^14.20.0 || ^16.13.0 || >=18.10.0.

Breaking14
Keyframes names are now prefixed with the component's scope name, so code relying on the original names no longer matches.
Removes the Angular compiler option enableIvy since Ivy is the only rendering engine.
enableIvy
Removes canParse from all translation parsers in @angular/localize/tools; use analyze instead, and hint in parse is now mandatory.
canParseanalyzeparsehint@angular/localize/tools
RouterOutlet no longer instantiates the activated component immediately during navigation; it waits until change detection runs.
RouterOutlet
relativeLinkResolution is no longer configurable in the Router.
relativeLinkResolution
Renames rawSrc to ngSrc in the NgOptimizedImage directive.
NgOptimizedImagerawSrcngSrc
Removes the enableIvy options.
enableIvy
Removes the deprecated relativeLinkResolution option.
relativeLinkResolution
Invalid constructors for DI may now report compilation errors when the inherited constructor cannot be used for DI.
@Injectable()@Directive()
Iframe usages with security-sensitive attributes applied via attribute or property binding may need updates for stricter iframe binding rules.
Iframe usages with src or srcdoc preceding other attributes may need updates for stricter iframe binding rules.
srcsrcdoc
setDisabledState is always called when a ControlValueAccessor is attached; opt out via FormsModule.withConfig or ReactiveFormsModule.withConfig.
setDisabledStateControlValueAccessorFormsModule.withConfigReactiveFormsModule.withConfig
The title property is now required on ActivatedRouteSnapshot.
ActivatedRouteSnapshottitle
Merges RouterLinkWithHref into RouterLink.
RouterLinkWithHrefRouterLink
Security3
Changes URL sanitization to only block javascript: URLs.
Hardens attribute and property binding rules for <iframe> elements.
Hardens rules related to the attribute order on iframe elements.
Platform5
Adds support for TypeScript 4.9.
Drops Node.js 14.[15-19].x and 16.[10-12].x support; supported versions are 14.20.x, 16.13.x and 18.10.x.
TypeScript versions older than 4.8 are no longer supported.
Adds support for Node.js version 18.
Drops support for TypeScript 4.6 and 4.7.
Deprecated9
Deprecates class and InjectionToken guards and resolvers in favor of plain JavaScript functions using inject from @angular/core.
InjectionTokeninject
Deprecates CanLoad guards in the Router in favor of CanMatch.
CanLoadCanMatchcanLoadcanMatch
Deprecates router writable properties in favor of DI providers and router options.
routeReuseStrategytitleStrategyurlHandlingStrategyonSameUrlNavigationparamsInheritanceStrategyurlUpdateStrategycanceledNavigationResolutionmalformedUriErrorHandler
Deprecates public members of Router that are meant to be configured elsewhere.
Router
Deprecates the DATE_PIPE_DEFAULT_TIMEZONE token in favor of DATE_PIPE_DEFAULT_OPTIONS with a timezone field.
DATE_PIPE_DEFAULT_TIMEZONEDATE_PIPE_DEFAULT_OPTIONStimezone
Deprecates passing an NgModule to providedIn for @Injectable and InjectionToken; use providedIn: 'root' or NgModule.providers.
providedIn@InjectableInjectionTokenNgModule.providers
Deprecates the bit field signature of Injector.get() in favor of the new options object.
Injector.get()TestBed.inject()
Deprecates the RouterLinkWithHref directive; use the RouterLink directive instead.
RouterLinkWithHrefRouterLink
Deprecates providedIn: NgModule and providedIn: 'any' for injectable providers.
providedIn

Generated by DepDelta from published .d.ts files. Not mixed with prose notes.

  • removed: constructor RouterOutlet(parentContexts: ChildrenOutletContexts, location: ViewContainerRef, name: string, changeDetector: ChangeDetectorRef, environmentInjector: EnvironmentInjector)
  • removed: function ɵassignExtraOptionsToRouter(opts: ExtraOptions, router: Router): void
  • removed: property ExtraOptions.relativeLinkResolution?: 'legacy' | 'corrected'
  • removed: property Router.relativeLinkResolution: 'legacy' | 'corrected'
  • removed: property RouterLinkActive.linksWithHrefs: QueryList<RouterLinkWithHref>
  • removed: readonly property ActivatedRouteSnapshot.title?: string
  • removed: readonly property Router.events: Observable<Event_2>
  • removed: readonly property RouterLinkActive.isActive: boolean
  • changed: class RouterLink implements OnChanges → class RouterLink implements OnChanges, OnDestroy
  • changed: constructor Router(rootComponentType: Type<any> | null, urlSerializer: UrlSerializer, rootContexts: ChildrenOutletContexts, location: Location_2, injector: Injector, compiler: Compiler, config: Routes) → constructor Router()
  • changed: constructor RouterLink(router: Router, route: ActivatedRoute, tabIndexAttribute: string | null | undefined, renderer: Renderer2, el: ElementRef) → constructor RouterLink(router: Router, route: ActivatedRoute, tabIndexAttribute: string | null | undefined, renderer: Renderer2, el: ElementRef, locationStrategy?: LocationStrategy | undefined)
  • changed: constructor RouterLinkActive(router: Router, element: ElementRef, renderer: Renderer2, cdr: ChangeDetectorRef, link?: RouterLink | undefined, linkWithHref?: RouterLinkWithHref | undefined) → constructor RouterLinkActive(router: Router, element: ElementRef, renderer: Renderer2, cdr: ChangeDetectorRef, link?: RouterLink | undefined)
  • changed: constructor RouterLinkWithHref(router: Router, route: ActivatedRoute, locationStrategy: LocationStrategy) → constructor RouterLinkWithHref(router: Router, route: ActivatedRoute, tabIndexAttribute: string | null | undefined, renderer: Renderer2, el: ElementRef, locationStrategy?: LocationStrategy | undefined)
  • changed: function provideRouter(routes: Routes, ...features: RouterFeatures[]): Provider[] → function provideRouter(routes: Routes, ...features: RouterFeatures[]): EnvironmentProviders
  • changed: method CanDeactivate.canDeactivate(component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree → method CanDeactivate.canDeactivate(component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree
  • changed: method RouterLink.onClick(): boolean → method RouterLink.onClick(button: number, ctrlKey: boolean, shiftKey: boolean, altKey: boolean, metaKey: boolean): boolean
  • changed: method RouterLinkWithHref.ngOnChanges(changes: SimpleChanges): any → method RouterLinkWithHref.ngOnChanges(changes: SimpleChanges): void
  • changed: property ExtraOptions.errorHandler?: ErrorHandler → property ExtraOptions.errorHandler?: (error: any) => any
  • changed: property Route.canActivate?: Array<CanActivateFn | any> → property Route.canActivate?: Array<CanActivateFn | DeprecatedGuard>
  • changed: property Route.canActivateChild?: Array<CanActivateChildFn | any> → property Route.canActivateChild?: Array<CanActivateChildFn | DeprecatedGuard>
  • changed: property Route.canDeactivate?: Array<CanDeactivateFn<any> | any> → property Route.canDeactivate?: Array<CanDeactivateFn<any> | DeprecatedGuard>
  • changed: property Route.canLoad?: Array<CanLoadFn | any> → property Route.canLoad?: Array<CanLoadFn | DeprecatedGuard>
  • changed: property Route.canMatch?: Array<Type<CanMatch> | InjectionToken<CanMatchFn> | CanMatchFn> → property Route.canMatch?: Array<CanMatchFn | DeprecatedGuard>
  • changed: property Route.loadComponent?: () => Type<unknown> | Observable<Type<unknown>> | Promise<Type<unknown>> → property Route.loadComponent?: () => Type<unknown> | Observable<Type<unknown> | DefaultExport<Type<unknown>>> | Promise<Type<unknown> | DefaultExport<Type<unknown>>>
  • changed: property Route.providers?: Array<Provider | ImportedNgModuleProviders> → property Route.providers?: Array<Provider | EnvironmentProviders>
  • changed: property Router.errorHandler: ErrorHandler → property Router.errorHandler: (error: any) => any
  • changed: property Router.onSameUrlNavigation: 'reload' | 'ignore' → property Router.onSameUrlNavigation: OnSameUrlNavigation
  • changed: property RouterConfigOptions.onSameUrlNavigation?: 'reload' | 'ignore' → property RouterConfigOptions.onSameUrlNavigation?: OnSameUrlNavigation
  • changed: property RouterLinkWithHref.target: string → property RouterLinkWithHref.target?: string
  • changed: static property RouterLink.ɵdir: i0.ɵɵDirectiveDeclaration<RouterLink, ':not(a):not(area)[routerLink]', never, { 'queryParams': 'queryParams'; 'fragment': 'fragment'; 'queryParamsHandling': 'queryParamsHandling'; 'state': 'state'; 'relativeTo': 'relativeTo'; 'preserveFragment': 'preserveFragment'; 'skipLocationChange': 'skipLocationChange'; 'replaceUrl': 'replaceUrl'; 'routerLink': 'routerLink' }… → static property RouterLink.ɵdir: i0.ɵɵDirectiveDeclaration<RouterLink, '[routerLink]', never, { 'target': 'target'; 'queryParams': 'queryParams'; 'fragment': 'fragment'; 'queryParamsHandling': 'queryParamsHandling'; 'state': 'state'; 'relativeTo': 'relativeTo'; 'preserveFragment': 'preserveFragment'; 'skipLocationChange': 'skipLocationChange'; 'replaceUrl': 'replaceUrl'; 'routerLink': 'routerLink…
  • changed: static property RouterLink.ɵfac: i0.ɵɵFactoryDeclaration<RouterLink, [null, null, { attribute: 'tabindex' }, null, null]> → static property RouterLink.ɵfac: i0.ɵɵFactoryDeclaration<RouterLink, [null, null, { attribute: 'tabindex' }, null, null, null]>
  • changed: static property RouterLinkActive.ɵdir: i0.ɵɵDirectiveDeclaration<RouterLinkActive, '[routerLinkActive]', ['routerLinkActive'], { 'routerLinkActiveOptions': 'routerLinkActiveOptions'; 'ariaCurrentWhenActive': 'ariaCurrentWhenActive'; 'routerLinkActive': 'routerLinkActive' }, { 'isActiveChange': 'isActiveChange' }, ['links', 'linksWithHrefs'], never, true> → static property RouterLinkActive.ɵdir: i0.ɵɵDirectiveDeclaration<RouterLinkActive, '[routerLinkActive]', ['routerLinkActive'], { 'routerLinkActiveOptions': 'routerLinkActiveOptions'; 'ariaCurrentWhenActive': 'ariaCurrentWhenActive'; 'routerLinkActive': 'routerLinkActive' }, { 'isActiveChange': 'isActiveChange' }, ['links'], never, true, never>
  • changed: static property RouterLinkActive.ɵfac: i0.ɵɵFactoryDeclaration<RouterLinkActive, [null, null, null, null, { optional: true }, { optional: true }]> → static property RouterLinkActive.ɵfac: i0.ɵɵFactoryDeclaration<RouterLinkActive, [null, null, null, null, { optional: true }]>
  • changed: static property RouterLinkWithHref.ɵdir: i0.ɵɵDirectiveDeclaration<RouterLinkWithHref, 'a[routerLink],area[routerLink]', never, { 'target': 'target'; 'queryParams': 'queryParams'; 'fragment': 'fragment'; 'queryParamsHandling': 'queryParamsHandling'; 'state': 'state'; 'relativeTo': 'relativeTo'; 'preserveFragment': 'preserveFragment'; 'skipLocationChange': 'skipLocationChange'; 'replaceUrl': 'repl… → static property RouterLinkWithHref.ɵdir: i0.ɵɵDirectiveDeclaration<RouterLink, '[routerLink]', never, { 'target': 'target'; 'queryParams': 'queryParams'; 'fragment': 'fragment'; 'queryParamsHandling': 'queryParamsHandling'; 'state': 'state'; 'relativeTo': 'relativeTo'; 'preserveFragment': 'preserveFragment'; 'skipLocationChange': 'skipLocationChange'; 'replaceUrl': 'replaceUrl'; 'routerLink': 'ro…
  • changed: static property RouterLinkWithHref.ɵfac: i0.ɵɵFactoryDeclaration<RouterLinkWithHref, never> → static property RouterLinkWithHref.ɵfac: i0.ɵɵFactoryDeclaration<RouterLink, [null, null, { attribute: 'tabindex' }, null, null, null]>
  • changed: static property RouterModule.ɵmod: i0.ɵɵNgModuleDeclaration<RouterModule, never, [typeof i1.RouterOutlet, typeof i2.RouterLink, typeof i2.RouterLinkWithHref, typeof i3.RouterLinkActive, typeof i4.ɵEmptyOutletComponent], [typeof i1.RouterOutlet, typeof i2.RouterLink, typeof i2.RouterLinkWithHref, typeof i3.RouterLinkActive, typeof i4.ɵEmptyOutletComponent]> → static property RouterModule.ɵmod: i0.ɵɵNgModuleDeclaration<RouterModule, never, [typeof i1.RouterOutlet, typeof i2.RouterLink, typeof i3.RouterLinkActive, typeof i4.ɵEmptyOutletComponent], [typeof i1.RouterOutlet, typeof i2.RouterLink, typeof i3.RouterLinkActive, typeof i4.ɵEmptyOutletComponent]>
  • changed: static property RouterOutlet.ɵdir: i0.ɵɵDirectiveDeclaration<RouterOutlet, 'router-outlet', ['outlet'], {}, { 'activateEvents': 'activate'; 'deactivateEvents': 'deactivate'; 'attachEvents': 'attach'; 'detachEvents': 'detach' }, never, never, true> → static property RouterOutlet.ɵdir: i0.ɵɵDirectiveDeclaration<RouterOutlet, 'router-outlet', ['outlet'], { 'name': 'name' }, { 'activateEvents': 'activate'; 'deactivateEvents': 'deactivate'; 'attachEvents': 'attach'; 'detachEvents': 'detach' }, never, never, true, never>
  • changed: static property RouterOutlet.ɵfac: i0.ɵɵFactoryDeclaration<RouterOutlet, [null, null, { attribute: 'name' }, null, null]> → static property RouterOutlet.ɵfac: i0.ɵɵFactoryDeclaration<RouterOutlet, never>
  • changed: static property ɵEmptyOutletComponent.ɵcmp: i0.ɵɵComponentDeclaration<ɵEmptyOutletComponent, 'ng-component', never, {}, {}, never, never, true> → static property ɵEmptyOutletComponent.ɵcmp: i0.ɵɵComponentDeclaration<ɵEmptyOutletComponent, 'ng-component', never, {}, {}, never, never, true, never>
  • changed: type CanDeactivateFn<T> = (component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot) => Observable<boolean | UrlTree> | Pro… → type CanDeactivateFn<T> = (component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot) => Observable<boolean | UrlTree> | Prom…
  • changed: type LoadChildrenCallback = () => Type<any> | NgModuleFactory<any> | Routes | Observable<Type<any> | Routes> | Promise<NgModuleFactory<any> | Type<any> | Routes> → type LoadChildrenCallback = () => Type<any> | NgModuleFactory<any> | Routes | Observable<Type<any> | Routes | DefaultExport<Type<any>> | DefaultExport<Routes>> | Promise<NgModuleFactory<a…
  • changed: type ResolveData = { [key: string | symbol]: any | ResolveFn<unknown> } → type ResolveData = { [key: string | symbol]: ResolveFn<unknown> | DeprecatedGuard }
  • changed: type RouterFeatures = PreloadingFeature | DebugTracingFeature | InitialNavigationFeature | InMemoryScrollingFeature | RouterConfigurationFeature → type RouterFeatures = PreloadingFeature | DebugTracingFeature | InitialNavigationFeature | InMemoryScrollingFeature | RouterConfigurationFeature | NavigationErrorHandlerFeature
  • added: class NavigationSkipped extends RouterEvent
  • added: const enum NavigationSkippedCode
  • added: constructor NavigationSkipped(id: number, url: string, reason: string, code?: NavigationSkippedCode | undefined)
  • added: constructor UrlTree(root?: UrlSegmentGroup, queryParams?: Params, fragment?: string | null)
  • added: function withHashLocation(): RouterConfigurationFeature
  • added: function withNavigationErrorHandler(fn: (error: NavigationError) => void): NavigationErrorHandlerFeature
  • added: function ɵafterNextNavigation(router: Router, action: () => void): void
  • added: get ActivatedRouteSnapshot.title(): string | undefined
  • added: get Router.events(): Observable<Event_2>
  • added: get RouterLinkActive.isActive(): boolean
  • added: interface DefaultExport<T>
  • added: member EventType.NavigationSkipped = 16
  • added: member NavigationSkippedCode.IgnoredByUrlHandlingStrategy = 1
  • added: member NavigationSkippedCode.IgnoredSameUrlNavigation = 0
  • added: method RouterLink.ngOnDestroy(): any
  • added: method RouterOutlet.ngOnChanges(changes: SimpleChanges): void
  • added: property DefaultExport.default: T
  • added: property NavigationBehaviorOptions.onSameUrlNavigation?: Extract<OnSameUrlNavigation, 'reload'>
  • added: property NavigationSkipped.reason: string
  • added: property RouterLink.href: string | null
  • added: property RouterLink.target?: string
  • added: property RouterOutlet.name: string
  • added: readonly property NavigationSkipped.code?: NavigationSkippedCode | undefined
  • added: readonly property NavigationSkipped.type = EventType.NavigationSkipped
  • added: static property RouteReuseStrategy.ɵfac: i0.ɵɵFactoryDeclaration<RouteReuseStrategy, never>
  • added: static property RouteReuseStrategy.ɵprov: i0.ɵɵInjectableDeclaration<RouteReuseStrategy>
  • added: static property UrlHandlingStrategy.ɵfac: i0.ɵɵFactoryDeclaration<UrlHandlingStrategy, never>
  • added: static property UrlHandlingStrategy.ɵprov: i0.ɵɵInjectableDeclaration<UrlHandlingStrategy>
  • added: type DeprecatedGuard = ProviderToken<any> | any
  • added: type NavigationErrorHandlerFeature = RouterFeature<RouterFeatureKind.NavigationErrorHandlerFeature>
  • added: type OnSameUrlNavigation = 'reload' | 'ignore'
  • added: type RouterHashLocationFeature = RouterFeature<RouterFeatureKind.RouterHashLocationFeature>
  • removed: function setupTestingRouterInternal(urlSerializer: UrlSerializer, contexts: ChildrenOutletContexts, location: Location_2, compiler: Compiler, injector: Injector, routes: Route[][], titleStrategy: TitleStrategy, opts?: ExtraOptions | UrlHandlingStrategy, urlHandlingStrategy?: UrlHandlingStrategy, routeReuseStrategy?: RouteReuseStrategy): Router
  • added: class RouterTestingHarness
  • added: get RouterTestingHarness.routeDebugElement(): DebugElement | null
  • added: get RouterTestingHarness.routeNativeElement(): HTMLElement | null
  • added: method RouterTestingHarness.detectChanges(): void
  • added: method RouterTestingHarness.navigateByUrl(url: string): Promise<null | {}>
  • added: method RouterTestingHarness.navigateByUrl<T>(url: string, requiredRoutedComponentType: Type<T>): Promise<T>
  • added: static method RouterTestingHarness.create(initialUrl?: string): Promise<RouterTestingHarness>