Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions aio/content/guide/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ v15 - v18
| `@angular/router` | [`resolver` argument in `RouterOutletContract.activateWith`](#router) | <!-- v14 --> v16 |
| `@angular/router` | [`resolver` field of the `OutletContext` class](#router) | <!-- v14 --> v16 |
| `@angular/router` | [`RouterLinkWithHref` directive](#router) | <!-- v15 --> v17 |
| `@angular/router` | [`provideRoutes` function](#router) | <!-- v15 --> v17 |
| `@angular/service-worker` | [`SwUpdate#activated`](api/service-worker/SwUpdate#activated) | <!-- v13 --> v16 |
| `@angular/service-worker` | [`SwUpdate#available`](api/service-worker/SwUpdate#available) | <!-- v13 --> v16 |
| template syntax | [`/deep/`, `>>>`, and `::ng-deep`](#deep-component-style-selector) | <!-- v7 --> unspecified |
Expand Down Expand Up @@ -167,6 +168,7 @@ In the [API reference section](api) of this site, deprecated APIs are indicated
| [`resolver` argument in `RouterOutletContract.activateWith`](api/router/RouterOutletContract#activatewith) | No replacement needed | v14 | Component factories are not required to create an instance of a component dynamically. Passing a factory resolver via `resolver` argument is no longer needed. |
| [`resolver` field of the `OutletContext` class](api/router/OutletContext#resolver) | No replacement needed | v14 | Component factories are not required to create an instance of a component dynamically. Passing a factory resolver via `resolver` class field is no longer needed. |
| [`RouterLinkWithHref` directive](api/router/RouterLinkWithHref) | Use `RouterLink` instead. | v15 | The `RouterLinkWithHref` directive code was merged into `RouterLink`. Now the `RouterLink` directive can be used for all elements that have `routerLink` attribute. |
| [`provideRoutes` function](api/router/provideRoutes) | Use `ROUTES` `InjectionToken` instead. | v15 | The `provideRoutes` helper function is minimally useful and can be unintentionally used instead of `provideRouter` due to similar spelling. |


<a id="platform-browser"></a>
Expand Down
2 changes: 1 addition & 1 deletion goldens/public-api/router/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ export const PRIMARY_OUTLET = "primary";
// @public
export function provideRouter(routes: Routes, ...features: RouterFeatures[]): EnvironmentProviders;

// @public
// @public @deprecated
export function provideRoutes(routes: Routes): Provider[];

// @public
Expand Down
6 changes: 3 additions & 3 deletions packages/core/test/bundling/router/bundle.golden_symbols.json
Original file line number Diff line number Diff line change
Expand Up @@ -1577,9 +1577,6 @@
{
"name": "promise"
},
{
"name": "provideRoutes"
},
{
"name": "redirectIfUrlTree"
},
Expand Down Expand Up @@ -1640,6 +1637,9 @@
{
"name": "rootRoute"
},
{
"name": "routes"
},
{
"name": "rxSubscriber"
},
Expand Down
29 changes: 28 additions & 1 deletion packages/router/src/provide_router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ const NG_DEV_MODE = typeof ngDevMode === 'undefined' || ngDevMode;
*/
export function provideRouter(routes: Routes, ...features: RouterFeatures[]): EnvironmentProviders {
return makeEnvironmentProviders([
provideRoutes(routes), {provide: ActivatedRoute, useFactory: rootRoute, deps: [Router]},
{provide: ROUTES, multi: true, useValue: routes},
NG_DEV_MODE ? {provide: ROUTER_IS_PROVIDED, useValue: true} : [],
{provide: ActivatedRoute, useFactory: rootRoute, deps: [Router]},
{provide: APP_BOOTSTRAP_LISTENER, multi: true, useFactory: getBootstrapListener},
features.map(feature => feature.ɵproviders),
// TODO: All options used by the `assignExtraOptionsToRouter` factory need to be reviewed for
Expand Down Expand Up @@ -92,6 +94,28 @@ function routerFeature<FeatureKind extends RouterFeatureKind>(
return {ɵkind: kind, ɵproviders: providers};
}


/**
* An Injection token used to indicate whether `provideRouter` or `RouterModule.forRoot` was ever
* called.
*/
export const ROUTER_IS_PROVIDED =
new InjectionToken<boolean>('', {providedIn: 'root', factory: () => false});

const routerIsProvidedDevModeCheck = {
provide: ENVIRONMENT_INITIALIZER,
multi: true,
useFactory() {
return () => {
if (!inject(ROUTER_IS_PROVIDED)) {
console.warn(
'`provideRoutes` was called without `provideRouter` or `RouterModule.forRoot`. ' +
'This is likely a mistake.');
}
};
}
};

/**
* Registers a [DI provider](guide/glossary#provider) for a set of routes.
* @param routes The route configuration to provide.
Expand All @@ -105,11 +129,14 @@ function routerFeature<FeatureKind extends RouterFeatureKind>(
* class LazyLoadedChildModule {}
* ```
*
* @deprecated If necessary, provide routes using the `ROUTES` `InjectionToken`.
* @see `ROUTES`
* @publicApi
*/
export function provideRoutes(routes: Routes): Provider[] {
return [
{provide: ROUTES, multi: true, useValue: routes},
NG_DEV_MODE ? routerIsProvidedDevModeCheck : [],
];
}

Expand Down
14 changes: 10 additions & 4 deletions packages/router/src/router_module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import {RouterLinkActive} from './directives/router_link_active';
import {RouterOutlet} from './directives/router_outlet';
import {RuntimeErrorCode} from './errors';
import {Routes} from './models';
import {getBootstrapListener, provideRoutes, rootRoute, withDebugTracing, withDisabledInitialNavigation, withEnabledBlockingInitialNavigation, withPreloading} from './provide_router';
import {getBootstrapListener, rootRoute, ROUTER_IS_PROVIDED, withDebugTracing, withDisabledInitialNavigation, withEnabledBlockingInitialNavigation, withPreloading} from './provide_router';
import {Router, setupRouter} from './router';
import {ExtraOptions, ROUTER_CONFIGURATION} from './router_config';
import {RouterConfigLoader} from './router_config_loader';
import {RouterConfigLoader, ROUTES} from './router_config_loader';
import {ChildrenOutletContexts} from './router_outlet_context';
import {ROUTER_SCROLLER, RouterScroller} from './router_scroller';
import {ActivatedRoute} from './router_state';
Expand Down Expand Up @@ -48,6 +48,9 @@ export const ROUTER_PROVIDERS: Provider[] = [
ChildrenOutletContexts,
{provide: ActivatedRoute, useFactory: rootRoute, deps: [Router]},
RouterConfigLoader,
// Only used to warn when `provideRoutes` is used without `RouterModule` or `provideRouter`. Can
// be removed when `provideRoutes` is removed.
NG_DEV_MODE ? {provide: ROUTER_IS_PROVIDED, useValue: true} : [],
];

export function routerNgProbeToken() {
Expand Down Expand Up @@ -106,7 +109,7 @@ export class RouterModule {
providers: [
ROUTER_PROVIDERS,
NG_DEV_MODE ? (config?.enableTracing ? withDebugTracing().ɵproviders : []) : [],
provideRoutes(routes),
{provide: ROUTES, multi: true, useValue: routes},
{
provide: ROUTER_FORROOT_GUARD,
useFactory: provideForRootGuard,
Expand Down Expand Up @@ -140,7 +143,10 @@ export class RouterModule {
*
*/
static forChild(routes: Routes): ModuleWithProviders<RouterModule> {
return {ngModule: RouterModule, providers: [provideRoutes(routes)]};
return {
ngModule: RouterModule,
providers: [{provide: ROUTES, multi: true, useValue: routes}],
};
}
}

Expand Down
33 changes: 25 additions & 8 deletions packages/router/test/router_preloader.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import {provideLocationMocks} from '@angular/common/testing';
import {Compiler, Component, Injectable, InjectionToken, Injector, NgModule, NgModuleFactory, NgModuleRef, Type} from '@angular/core';
import {fakeAsync, inject, TestBed, tick} from '@angular/core/testing';
import {PreloadAllModules, PreloadingStrategy, provideRoutes, RouterPreloader, withPreloading} from '@angular/router';
import {PreloadAllModules, PreloadingStrategy, RouterPreloader, ROUTES, withPreloading} from '@angular/router';
import {BehaviorSubject, Observable, of, throwError} from 'rxjs';
import {catchError, delay, filter, switchMap, take} from 'rxjs/operators';

Expand Down Expand Up @@ -46,7 +46,13 @@ describe('RouterPreloader', () => {
describe('configurations with canLoad guard', () => {
@NgModule({
declarations: [LazyLoadedCmp],
providers: [provideRoutes([{path: 'LoadedModule1', component: LazyLoadedCmp}])]
providers: [
{
provide: ROUTES,
multi: true,
useValue: [{path: 'LoadedModule1', component: LazyLoadedCmp}]
},
]
})
class LoadedModule {
}
Expand Down Expand Up @@ -563,10 +569,14 @@ describe('RouterPreloader', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [
provideRoutes([
{path: 'lazy1', loadChildren: jasmine.createSpy('expected1')},
{path: 'lazy2', loadChildren: () => LoadedModule}
]),
{
provide: ROUTES,
multi: true,
useValue: [
{path: 'lazy1', loadChildren: jasmine.createSpy('expected1')},
{path: 'lazy2', loadChildren: () => LoadedModule}
]
},
{provide: PreloadingStrategy, useExisting: PreloadAllModules},
]
});
Expand All @@ -587,7 +597,10 @@ describe('RouterPreloader', () => {

describe('should copy loaded configs', () => {
const configs = [{path: 'LoadedModule1', component: LazyLoadedCmp}];
@NgModule({declarations: [LazyLoadedCmp], providers: [provideRoutes(configs)]})
@NgModule({
declarations: [LazyLoadedCmp],
providers: [{provide: ROUTES, multi: true, useValue: configs}]
})
class LoadedModule {
}

Expand Down Expand Up @@ -621,7 +634,11 @@ describe('RouterPreloader', () => {
'should work with lazy loaded modules that don\'t provide RouterModule.forChild()', () => {
@NgModule({
declarations: [LazyLoadedCmp],
providers: [provideRoutes([{path: 'LoadedModule1', component: LazyLoadedCmp}])]
providers: [{
provide: ROUTES,
multi: true,
useValue: [{path: 'LoadedModule1', component: LazyLoadedCmp}]
}]
})
class LoadedModule {
}
Expand Down
13 changes: 11 additions & 2 deletions packages/router/test/standalone.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
import {Component, Injectable, NgModule} from '@angular/core';
import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
import {By} from '@angular/platform-browser';
import {NavigationEnd, Router, RouterModule} from '@angular/router';
import {provideRoutes, Router, RouterModule, ROUTES} from '@angular/router';
import {RouterTestingModule} from '@angular/router/testing';
import {filter, first} from 'rxjs/operators';

@Component({template: '<div>simple standalone</div>', standalone: true})
export class SimpleStandaloneComponent {
Expand Down Expand Up @@ -372,6 +371,16 @@ describe('standalone in Router API', () => {
});
});

describe('provideRoutes', () => {
it('warns if provideRoutes is used without provideRouter, RouterTestingModule, or RouterModule.forRoot',
() => {
spyOn(console, 'warn');
TestBed.configureTestingModule({providers: [provideRoutes([])]});
TestBed.inject(ROUTES);
expect(console.warn).toHaveBeenCalled();
});
});

function advance(fixture: ComponentFixture<unknown>) {
tick();
fixture.detectChanges();
Expand Down
6 changes: 3 additions & 3 deletions packages/router/testing/src/router_testing_module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import {Location} from '@angular/common';
import {provideLocationMocks} from '@angular/common/testing';
import {Compiler, Injector, ModuleWithProviders, NgModule, Optional} from '@angular/core';
import {ChildrenOutletContexts, ExtraOptions, NoPreloading, provideRoutes, Route, Router, ROUTER_CONFIGURATION, RouteReuseStrategy, RouterModule, ROUTES, Routes, TitleStrategy, UrlHandlingStrategy, UrlSerializer, ɵassignExtraOptionsToRouter as assignExtraOptionsToRouter, ɵflatten as flatten, ɵROUTER_PROVIDERS as ROUTER_PROVIDERS, ɵwithPreloading as withPreloading} from '@angular/router';
import {ChildrenOutletContexts, ExtraOptions, NoPreloading, Route, Router, ROUTER_CONFIGURATION, RouteReuseStrategy, RouterModule, ROUTES, Routes, TitleStrategy, UrlHandlingStrategy, UrlSerializer, ɵassignExtraOptionsToRouter as assignExtraOptionsToRouter, ɵflatten as flatten, ɵROUTER_PROVIDERS as ROUTER_PROVIDERS, ɵwithPreloading as withPreloading} from '@angular/router';

import {EXTRA_ROUTER_TESTING_PROVIDERS} from './extra_router_testing_providers';

Expand Down Expand Up @@ -124,7 +124,7 @@ export function setupTestingRouter(
]
},
withPreloading(NoPreloading).ɵproviders,
provideRoutes([]),
{provide: ROUTES, multi: true, useValue: []},
]
})
export class RouterTestingModule {
Expand All @@ -133,7 +133,7 @@ export class RouterTestingModule {
return {
ngModule: RouterTestingModule,
providers: [
provideRoutes(routes),
{provide: ROUTES, multi: true, useValue: routes},
{provide: ROUTER_CONFIGURATION, useValue: config ? config : {}},
]
};
Expand Down