UNPKG

@angular/router

Version:
1,500 lines (1,495 loc) 142 kB
/** * @license Angular v20.0.4 * (c) 2010-2025 Google LLC. https://angular.io/ * License: MIT */ import * as i0 from '@angular/core'; import { ProviderToken, Type, NgModuleFactory, Provider, EnvironmentProviders, EnvironmentInjector, InjectionToken, Signal, ComponentRef, EventEmitter, OnDestroy, OnInit, SimpleChanges, OnChanges, Renderer2, ElementRef, AfterContentInit, QueryList, ChangeDetectorRef, ModuleWithProviders } from '@angular/core'; import { Observable } from 'rxjs'; import { LocationStrategy } from '@angular/common'; /** * The primary routing outlet. * * @publicApi */ declare const PRIMARY_OUTLET = "primary"; /** * A collection of matrix and query URL parameters. * @see {@link convertToParamMap} * @see {@link ParamMap} * * @publicApi */ type Params = { [key: string]: any; }; /** * A map that provides access to the required and optional parameters * specific to a route. * The map supports retrieving a single value with `get()` * or multiple values with `getAll()`. * * @see [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams) * * @publicApi */ interface ParamMap { /** * Reports whether the map contains a given parameter. * @param name The parameter name. * @returns True if the map contains the given parameter, false otherwise. */ has(name: string): boolean; /** * Retrieves a single value for a parameter. * @param name The parameter name. * @return The parameter's single value, * or the first value if the parameter has multiple values, * or `null` when there is no such parameter. */ get(name: string): string | null; /** * Retrieves multiple values for a parameter. * @param name The parameter name. * @return An array containing one or more values, * or an empty array if there is no such parameter. * */ getAll(name: string): string[]; /** Names of the parameters in the map. */ readonly keys: string[]; } /** * Converts a `Params` instance to a `ParamMap`. * @param params The instance to convert. * @returns The new map instance. * * @publicApi */ declare function convertToParamMap(params: Params): ParamMap; /** * Matches the route configuration (`route`) against the actual URL (`segments`). * * When no matcher is defined on a `Route`, this is the matcher used by the Router by default. * * @param segments The remaining unmatched segments in the current navigation * @param segmentGroup The current segment group being matched * @param route The `Route` to match against. * * @see {@link UrlMatchResult} * @see {@link Route} * * @returns The resulting match information or `null` if the `route` should not match. * @publicApi */ declare function defaultUrlMatcher(segments: UrlSegment[], segmentGroup: UrlSegmentGroup, route: Route): UrlMatchResult | null; /** * A set of options which specify how to determine if a `UrlTree` is active, given the `UrlTree` * for the current router state. * * @publicApi * @see {@link Router#isActive} */ interface IsActiveMatchOptions { /** * Defines the strategy for comparing the matrix parameters of two `UrlTree`s. * * The matrix parameter matching is dependent on the strategy for matching the * segments. That is, if the `paths` option is set to `'subset'`, only * the matrix parameters of the matching segments will be compared. * * - `'exact'`: Requires that matching segments also have exact matrix parameter * matches. * - `'subset'`: The matching segments in the router's active `UrlTree` may contain * extra matrix parameters, but those that exist in the `UrlTree` in question must match. * - `'ignored'`: When comparing `UrlTree`s, matrix params will be ignored. */ matrixParams: 'exact' | 'subset' | 'ignored'; /** * Defines the strategy for comparing the query parameters of two `UrlTree`s. * * - `'exact'`: the query parameters must match exactly. * - `'subset'`: the active `UrlTree` may contain extra parameters, * but must match the key and value of any that exist in the `UrlTree` in question. * - `'ignored'`: When comparing `UrlTree`s, query params will be ignored. */ queryParams: 'exact' | 'subset' | 'ignored'; /** * Defines the strategy for comparing the `UrlSegment`s of the `UrlTree`s. * * - `'exact'`: all segments in each `UrlTree` must match. * - `'subset'`: a `UrlTree` will be determined to be active if it * is a subtree of the active route. That is, the active route may contain extra * segments, but must at least have all the segments of the `UrlTree` in question. */ paths: 'exact' | 'subset'; /** * - `'exact'`: indicates that the `UrlTree` fragments must be equal. * - `'ignored'`: the fragments will not be compared when determining if a * `UrlTree` is active. */ fragment: 'exact' | 'ignored'; } /** * @description * * Represents the parsed URL. * * Since a router state is a tree, and the URL is nothing but a serialized state, the URL is a * serialized tree. * UrlTree is a data structure that provides a lot of affordances in dealing with URLs * * @usageNotes * ### Example * * ```ts * @Component({templateUrl:'template.html'}) * class MyComponent { * constructor(router: Router) { * const tree: UrlTree = * router.parseUrl('/team/33/(user/victor//support:help)?debug=true#fragment'); * const f = tree.fragment; // return 'fragment' * const q = tree.queryParams; // returns {debug: 'true'} * const g: UrlSegmentGroup = tree.root.children[PRIMARY_OUTLET]; * const s: UrlSegment[] = g.segments; // returns 2 segments 'team' and '33' * g.children[PRIMARY_OUTLET].segments; // returns 2 segments 'user' and 'victor' * g.children['support'].segments; // return 1 segment 'help' * } * } * ``` * * @publicApi */ declare class UrlTree { /** The root segment group of the URL tree */ root: UrlSegmentGroup; /** The query params of the URL */ queryParams: Params; /** The fragment of the URL */ fragment: string | null; constructor( /** The root segment group of the URL tree */ root?: UrlSegmentGroup, /** The query params of the URL */ queryParams?: Params, /** The fragment of the URL */ fragment?: string | null); get queryParamMap(): ParamMap; /** @docsNotRequired */ toString(): string; } /** * @description * * Represents the parsed URL segment group. * * See `UrlTree` for more information. * * @publicApi */ declare class UrlSegmentGroup { /** The URL segments of this group. See `UrlSegment` for more information */ segments: UrlSegment[]; /** The list of children of this group */ children: { [key: string]: UrlSegmentGroup; }; /** The parent node in the url tree */ parent: UrlSegmentGroup | null; constructor( /** The URL segments of this group. See `UrlSegment` for more information */ segments: UrlSegment[], /** The list of children of this group */ children: { [key: string]: UrlSegmentGroup; }); /** Whether the segment has child segments */ hasChildren(): boolean; /** Number of child segments */ get numberOfChildren(): number; /** @docsNotRequired */ toString(): string; } /** * @description * * Represents a single URL segment. * * A UrlSegment is a part of a URL between the two slashes. It contains a path and the matrix * parameters associated with the segment. * * @usageNotes * ### Example * * ```ts * @Component({templateUrl:'template.html'}) * class MyComponent { * constructor(router: Router) { * const tree: UrlTree = router.parseUrl('/team;id=33'); * const g: UrlSegmentGroup = tree.root.children[PRIMARY_OUTLET]; * const s: UrlSegment[] = g.segments; * s[0].path; // returns 'team' * s[0].parameters; // returns {id: 33} * } * } * ``` * * @publicApi */ declare class UrlSegment { /** The path part of a URL segment */ path: string; /** The matrix parameters associated with a segment */ parameters: { [name: string]: string; }; constructor( /** The path part of a URL segment */ path: string, /** The matrix parameters associated with a segment */ parameters: { [name: string]: string; }); get parameterMap(): ParamMap; /** @docsNotRequired */ toString(): string; } /** * @description * * Serializes and deserializes a URL string into a URL tree. * * The url serialization strategy is customizable. You can * make all URLs case insensitive by providing a custom UrlSerializer. * * See `DefaultUrlSerializer` for an example of a URL serializer. * * @publicApi */ declare abstract class UrlSerializer { /** Parse a url into a `UrlTree` */ abstract parse(url: string): UrlTree; /** Converts a `UrlTree` into a url */ abstract serialize(tree: UrlTree): string; static ɵfac: i0.ɵɵFactoryDeclaration<UrlSerializer, never>; static ɵprov: i0.ɵɵInjectableDeclaration<UrlSerializer>; } /** * @description * * A default implementation of the `UrlSerializer`. * * Example URLs: * * ``` * /inbox/33(popup:compose) * /inbox/33;open=true/messages/44 * ``` * * DefaultUrlSerializer uses parentheses to serialize secondary segments (e.g., popup:compose), the * colon syntax to specify the outlet, and the ';parameter=value' syntax (e.g., open=true) to * specify route specific parameters. * * @publicApi */ declare class DefaultUrlSerializer implements UrlSerializer { /** Parses a url into a `UrlTree` */ parse(url: string): UrlTree; /** Converts a `UrlTree` into a url */ serialize(tree: UrlTree): string; } /** * How to handle a navigation request to the current URL. One of: * * - `'ignore'` : The router ignores the request if it is the same as the current state. * - `'reload'` : The router processes the URL even if it is not different from the current state. * One example of when you might want to use this option is if a `canMatch` guard depends on the * application state and initially rejects navigation to a route. After fixing the state, you want * to re-navigate to the same URL so that the route with the `canMatch` guard can activate. * * Note that this only configures whether or not the Route reprocesses the URL and triggers related * actions and events like redirects, guards, and resolvers. By default, the router re-uses a * component instance when it re-navigates to the same component type without visiting a different * component first. This behavior is configured by the `RouteReuseStrategy`. In order to reload * routed components on same url navigation, you need to set `onSameUrlNavigation` to `'reload'` * _and_ provide a `RouteReuseStrategy` which returns `false` for `shouldReuseRoute`. Additionally, * resolvers and most guards for routes do not run unless the path or path params have changed * (configured by `runGuardsAndResolvers`). * * @publicApi * @see {@link RouteReuseStrategy} * @see {@link RunGuardsAndResolvers} * @see {@link NavigationBehaviorOptions} * @see {@link RouterConfigOptions} */ type OnSameUrlNavigation = 'reload' | 'ignore'; /** * The `InjectionToken` and `@Injectable` classes for guards are deprecated in favor * of plain JavaScript functions instead. Dependency injection can still be achieved using the * [`inject`](api/core/inject) function from `@angular/core` and an injectable class can be used as * a functional guard using [`inject`](api/core/inject): `canActivate: [() => * inject(myGuard).canActivate()]`. * * @deprecated * @see {@link CanMatchFn} * @see {@link CanLoadFn} * @see {@link CanActivateFn} * @see {@link CanActivateChildFn} * @see {@link CanDeactivateFn} * @see {@link /api/core/inject inject} * @publicApi */ type DeprecatedGuard = ProviderToken<any> | string; /** * The `InjectionToken` and `@Injectable` classes for resolvers are deprecated in favor * of plain JavaScript functions instead. Dependency injection can still be achieved using the * [`inject`](api/core/inject) function from `@angular/core` and an injectable class can be used as * a functional guard using [`inject`](api/core/inject): `myResolvedData: () => inject(MyResolver).resolve()`. * * @deprecated * @see {@link ResolveFn} * @see {@link /api/core/inject inject} * @publicApi */ type DeprecatedResolve = DeprecatedGuard | any; /** * The supported types that can be returned from a `Router` guard. * * @see [Routing guide](guide/routing/common-router-tasks#preventing-unauthorized-access) * @publicApi */ type GuardResult = boolean | UrlTree | RedirectCommand; /** * Can be returned by a `Router` guard to instruct the `Router` to redirect rather than continue * processing the path of the in-flight navigation. The `redirectTo` indicates _where_ the new * navigation should go to and the optional `navigationBehaviorOptions` can provide more information * about _how_ to perform the navigation. * * ```ts * const route: Route = { * path: "user/:userId", * component: User, * canActivate: [ * () => { * const router = inject(Router); * const authService = inject(AuthenticationService); * * if (!authService.isLoggedIn()) { * const loginPath = router.parseUrl("/login"); * return new RedirectCommand(loginPath, { * skipLocationChange: true, * }); * } * * return true; * }, * ], * }; * ``` * @see [Routing guide](guide/routing/common-router-tasks#preventing-unauthorized-access) * * @publicApi */ declare class RedirectCommand { readonly redirectTo: UrlTree; readonly navigationBehaviorOptions?: NavigationBehaviorOptions | undefined; constructor(redirectTo: UrlTree, navigationBehaviorOptions?: NavigationBehaviorOptions | undefined); } /** * Type used to represent a value which may be synchronous or async. * * @publicApi */ type MaybeAsync<T> = T | Observable<T> | Promise<T>; /** * Represents a route configuration for the Router service. * An array of `Route` objects, used in `Router.config` and for nested route configurations * in `Route.children`. * * @see {@link Route} * @see {@link Router} * @see [Router configuration guide](guide/routing/router-reference#configuration) * @publicApi */ type Routes = Route[]; /** * Represents the result of matching URLs with a custom matching function. * * * `consumed` is an array of the consumed URL segments. * * `posParams` is a map of positional parameters. * * @see {@link UrlMatcher} * @publicApi */ type UrlMatchResult = { consumed: UrlSegment[]; posParams?: { [name: string]: UrlSegment; }; }; /** * A function for matching a route against URLs. Implement a custom URL matcher * for `Route.matcher` when a combination of `path` and `pathMatch` * is not expressive enough. Cannot be used together with `path` and `pathMatch`. * * The function takes the following arguments and returns a `UrlMatchResult` object. * * *segments* : An array of URL segments. * * *group* : A segment group. * * *route* : The route to match against. * * The following example implementation matches HTML files. * * ```ts * export function htmlFiles(url: UrlSegment[]) { * return url.length === 1 && url[0].path.endsWith('.html') ? ({consumed: url}) : null; * } * * export const routes = [{ matcher: htmlFiles, component: AnyComponent }]; * ``` * * @publicApi */ type UrlMatcher = (segments: UrlSegment[], group: UrlSegmentGroup, route: Route) => UrlMatchResult | null; /** * * Represents static data associated with a particular route. * * @see {@link Route#data} * * @publicApi */ type Data = { [key: string | symbol]: any; }; /** * * Represents the resolved data associated with a particular route. * * Returning a `RedirectCommand` directs the router to cancel the current navigation and redirect to * the location provided in the `RedirectCommand`. Note that there are no ordering guarantees when * resolvers execute. If multiple resolvers would return a `RedirectCommand`, only the first one * returned will be used. * * @see {@link Route#resolve} * * @publicApi */ type ResolveData = { [key: string | symbol]: ResolveFn<unknown> | DeprecatedResolve; }; /** * An ES Module object with a default export of the given type. * * @see {@link Route#loadComponent} * @see {@link LoadChildrenCallback} * * @publicApi */ interface DefaultExport<T> { /** * Default exports are bound under the name `"default"`, per the ES Module spec: * https://tc39.es/ecma262/#table-export-forms-mapping-to-exportentry-records */ default: T; } /** * * A function that is called to resolve a collection of lazy-loaded routes. * Must be an arrow function of the following form: * `() => import('...').then(mod => mod.MODULE)` * or * `() => import('...').then(mod => mod.ROUTES)` * * For example: * * ```ts * [{ * path: 'lazy', * loadChildren: () => import('./lazy-route/lazy.module').then(mod => mod.LazyModule), * }]; * ``` * or * ```ts * [{ * path: 'lazy', * loadChildren: () => import('./lazy-route/lazy.routes').then(mod => mod.ROUTES), * }]; * ``` * * If the lazy-loaded routes are exported via a `default` export, the `.then` can be omitted: * ```ts * [{ * path: 'lazy', * loadChildren: () => import('./lazy-route/lazy.routes'), * }]; * ``` * * @see {@link Route#loadChildren} * @publicApi */ type LoadChildrenCallback = () => Type<any> | NgModuleFactory<any> | Routes | Observable<Type<any> | Routes | DefaultExport<Type<any>> | DefaultExport<Routes>> | Promise<NgModuleFactory<any> | Type<any> | Routes | DefaultExport<Type<any>> | DefaultExport<Routes>>; /** * * A function that returns a set of routes to load. * * @see {@link LoadChildrenCallback} * @publicApi */ type LoadChildren = LoadChildrenCallback; /** * * How to handle query parameters in a router link. * One of: * - `"merge"` : Merge new parameters with current parameters. * - `"preserve"` : Preserve current parameters. * - `"replace"` : Replace current parameters with new parameters. This is the default behavior. * - `""` : For legacy reasons, the same as `'replace'`. * * @see {@link UrlCreationOptions#queryParamsHandling} * @see {@link RouterLink} * @publicApi */ type QueryParamsHandling = 'merge' | 'preserve' | 'replace' | ''; /** * The type for the function that can be used to handle redirects when the path matches a `Route` config. * * The `RedirectFunction` does _not_ have access to the full * `ActivatedRouteSnapshot` interface. Some data are not accurately known * at the route matching phase. For example, resolvers are not run until * later, so any resolved title would not be populated. The same goes for lazy * loaded components. This is also true for all the snapshots up to the * root, so properties that include parents (root, parent, pathFromRoot) * are also excluded. And naturally, the full route matching hasn't yet * happened so firstChild and children are not available either. * * @see {@link Route#redirectTo} * @publicApi */ type RedirectFunction = (redirectData: Pick<ActivatedRouteSnapshot, 'routeConfig' | 'url' | 'params' | 'queryParams' | 'fragment' | 'data' | 'outlet' | 'title'>) => MaybeAsync<string | UrlTree>; /** * A policy for when to run guards and resolvers on a route. * * Guards and/or resolvers will always run when a route is activated or deactivated. When a route is * unchanged, the default behavior is the same as `paramsChange`. * * `paramsChange` : Rerun the guards and resolvers when path or * path param changes. This does not include query parameters. This option is the default. * - `always` : Run on every execution. * - `pathParamsChange` : Rerun guards and resolvers when the path params * change. This does not compare matrix or query parameters. * - `paramsOrQueryParamsChange` : Run when path, matrix, or query parameters change. * - `pathParamsOrQueryParamsChange` : Rerun guards and resolvers when the path params * change or query params have changed. This does not include matrix parameters. * * @see {@link Route#runGuardsAndResolvers} * @publicApi */ type RunGuardsAndResolvers = 'pathParamsChange' | 'pathParamsOrQueryParamsChange' | 'paramsChange' | 'paramsOrQueryParamsChange' | 'always' | ((from: ActivatedRouteSnapshot, to: ActivatedRouteSnapshot) => boolean); /** * A configuration object that defines a single route. * A set of routes are collected in a `Routes` array to define a `Router` configuration. * The router attempts to match segments of a given URL against each route, * using the configuration options defined in this object. * * Supports static, parameterized, redirect, and wildcard routes, as well as * custom route data and resolve methods. * * For detailed usage information, see the [Routing Guide](guide/routing/common-router-tasks). * * @usageNotes * * ### Simple Configuration * * The following route specifies that when navigating to, for example, * `/team/11/user/bob`, the router creates the 'Team' component * with the 'User' child component in it. * * ```ts * [{ * path: 'team/:id', * component: Team, * children: [{ * path: 'user/:name', * component: User * }] * }] * ``` * * ### Multiple Outlets * * The following route creates sibling components with multiple outlets. * When navigating to `/team/11(aux:chat/jim)`, the router creates the 'Team' component next to * the 'Chat' component. The 'Chat' component is placed into the 'aux' outlet. * * ```ts * [{ * path: 'team/:id', * component: Team * }, { * path: 'chat/:user', * component: Chat * outlet: 'aux' * }] * ``` * * ### Wild Cards * * The following route uses wild-card notation to specify a component * that is always instantiated regardless of where you navigate to. * * ```ts * [{ * path: '**', * component: WildcardComponent * }] * ``` * * ### Redirects * * The following route uses the `redirectTo` property to ignore a segment of * a given URL when looking for a child path. * * When navigating to '/team/11/legacy/user/jim', the router changes the URL segment * '/team/11/legacy/user/jim' to '/team/11/user/jim', and then instantiates * the Team component with the User child component in it. * * ```ts * [{ * path: 'team/:id', * component: Team, * children: [{ * path: 'legacy/user/:name', * redirectTo: 'user/:name' * }, { * path: 'user/:name', * component: User * }] * }] * ``` * * The redirect path can be relative, as shown in this example, or absolute. * If we change the `redirectTo` value in the example to the absolute URL segment '/user/:name', * the result URL is also absolute, '/user/jim'. * ### Empty Path * * Empty-path route configurations can be used to instantiate components that do not 'consume' * any URL segments. * * In the following configuration, when navigating to * `/team/11`, the router instantiates the 'AllUsers' component. * * ```ts * [{ * path: 'team/:id', * component: Team, * children: [{ * path: '', * component: AllUsers * }, { * path: 'user/:name', * component: User * }] * }] * ``` * * Empty-path routes can have children. In the following example, when navigating * to `/team/11/user/jim`, the router instantiates the wrapper component with * the user component in it. * * Note that an empty path route inherits its parent's parameters and data. * * ```ts * [{ * path: 'team/:id', * component: Team, * children: [{ * path: '', * component: WrapperCmp, * children: [{ * path: 'user/:name', * component: User * }] * }] * }] * ``` * * ### Matching Strategy * * The default path-match strategy is 'prefix', which means that the router * checks URL elements from the left to see if the URL matches a specified path. * For example, '/team/11/user' matches 'team/:id'. * * ```ts * [{ * path: '', * pathMatch: 'prefix', //default * redirectTo: 'main' * }, { * path: 'main', * component: Main * }] * ``` * * You can specify the path-match strategy 'full' to make sure that the path * covers the whole unconsumed URL. It is important to do this when redirecting * empty-path routes. Otherwise, because an empty path is a prefix of any URL, * the router would apply the redirect even when navigating to the redirect destination, * creating an endless loop. * * In the following example, supplying the 'full' `pathMatch` strategy ensures * that the router applies the redirect if and only if navigating to '/'. * * ```ts * [{ * path: '', * pathMatch: 'full', * redirectTo: 'main' * }, { * path: 'main', * component: Main * }] * ``` * * ### Componentless Routes * * You can share parameters between sibling components. * For example, suppose that two sibling components should go next to each other, * and both of them require an ID parameter. You can accomplish this using a route * that does not specify a component at the top level. * * In the following example, 'MainChild' and 'AuxChild' are siblings. * When navigating to 'parent/10/(a//aux:b)', the route instantiates * the main child and aux child components next to each other. * For this to work, the application component must have the primary and aux outlets defined. * * ```ts * [{ * path: 'parent/:id', * children: [ * { path: 'a', component: MainChild }, * { path: 'b', component: AuxChild, outlet: 'aux' } * ] * }] * ``` * * The router merges the parameters, data, and resolve of the componentless * parent into the parameters, data, and resolve of the children. * * This is especially useful when child components are defined * with an empty path string, as in the following example. * With this configuration, navigating to '/parent/10' creates * the main child and aux components. * * ```ts * [{ * path: 'parent/:id', * children: [ * { path: '', component: MainChild }, * { path: '', component: AuxChild, outlet: 'aux' } * ] * }] * ``` * * ### Lazy Loading * * Lazy loading speeds up application load time by splitting the application * into multiple bundles and loading them on demand. * To use lazy loading, provide the `loadChildren` property in the `Route` object, * instead of the `children` property. * * Given the following example route, the router will lazy load * the associated module on demand using the browser native import system. * * ```ts * [{ * path: 'lazy', * loadChildren: () => import('./lazy-route/lazy.module').then(mod => mod.LazyModule), * }]; * ``` * * @publicApi */ interface Route { /** * Used to define a page title for the route. This can be a static string or an `Injectable` that * implements `Resolve`. * * @see {@link TitleStrategy} */ title?: string | Type<Resolve<string>> | ResolveFn<string>; /** * The path to match against. Cannot be used together with a custom `matcher` function. * A URL string that uses router matching notation. * Can be a wild card (`**`) that matches any URL (see Usage Notes below). * Default is "/" (the root path). * */ path?: string; /** * The path-matching strategy, one of 'prefix' or 'full'. * Default is 'prefix'. * * By default, the router checks URL elements from the left to see if the URL * matches a given path and stops when there is a config match. Importantly there must still be a * config match for each segment of the URL. For example, '/team/11/user' matches the prefix * 'team/:id' if one of the route's children matches the segment 'user'. That is, the URL * '/team/11/user' matches the config * `{path: 'team/:id', children: [{path: ':user', component: User}]}` * but does not match when there are no children as in `{path: 'team/:id', component: Team}`. * * The path-match strategy 'full' matches against the entire URL. * It is important to do this when redirecting empty-path routes. * Otherwise, because an empty path is a prefix of any URL, * the router would apply the redirect even when navigating * to the redirect destination, creating an endless loop. * */ pathMatch?: 'prefix' | 'full'; /** * A custom URL-matching function. Cannot be used together with `path`. */ matcher?: UrlMatcher; /** * The component to instantiate when the path matches. * Can be empty if child routes specify components. */ component?: Type<any>; /** * An object specifying a lazy-loaded component. */ loadComponent?: () => Type<unknown> | Observable<Type<unknown> | DefaultExport<Type<unknown>>> | Promise<Type<unknown> | DefaultExport<Type<unknown>>>; /** * A URL or function that returns a URL to redirect to when the path matches. * * Absolute if the URL begins with a slash (/) or the function returns a `UrlTree`, otherwise * relative to the path URL. * * The `RedirectFunction` is run in an injection context so it can call `inject` to get any * required dependencies. * * When not present, router does not redirect. */ redirectTo?: string | RedirectFunction; /** * Name of a `RouterOutlet` object where the component can be placed * when the path matches. */ outlet?: string; /** * An array of `CanActivateFn` or DI tokens used to look up `CanActivate()` * handlers, in order to determine if the current user is allowed to * activate the component. By default, any user can activate. * * When using a function rather than DI tokens, the function can call `inject` to get any required * dependencies. This `inject` call must be done in a synchronous context. */ canActivate?: Array<CanActivateFn | DeprecatedGuard>; /** * An array of `CanMatchFn` or DI tokens used to look up `CanMatch()` * handlers, in order to determine if the current user is allowed to * match the `Route`. By default, any route can match. * * When using a function rather than DI tokens, the function can call `inject` to get any required * dependencies. This `inject` call must be done in a synchronous context. */ canMatch?: Array<CanMatchFn | DeprecatedGuard>; /** * An array of `CanActivateChildFn` or DI tokens used to look up `CanActivateChild()` handlers, * in order to determine if the current user is allowed to activate * a child of the component. By default, any user can activate a child. * * When using a function rather than DI tokens, the function can call `inject` to get any required * dependencies. This `inject` call must be done in a synchronous context. */ canActivateChild?: Array<CanActivateChildFn | DeprecatedGuard>; /** * An array of `CanDeactivateFn` or DI tokens used to look up `CanDeactivate()` * handlers, in order to determine if the current user is allowed to * deactivate the component. By default, any user can deactivate. * * When using a function rather than DI tokens, the function can call `inject` to get any required * dependencies. This `inject` call must be done in a synchronous context. */ canDeactivate?: Array<CanDeactivateFn<any> | DeprecatedGuard>; /** * An array of `CanLoadFn` or DI tokens used to look up `CanLoad()` * handlers, in order to determine if the current user is allowed to * load the component. By default, any user can load. * * When using a function rather than DI tokens, the function can call `inject` to get any required * dependencies. This `inject` call must be done in a synchronous context. * @deprecated Use `canMatch` instead */ canLoad?: Array<CanLoadFn | DeprecatedGuard>; /** * Additional developer-defined data provided to the component via * `ActivatedRoute`. By default, no additional data is passed. */ data?: Data; /** * A map of DI tokens used to look up data resolvers. See `Resolve`. */ resolve?: ResolveData; /** * An array of child `Route` objects that specifies a nested route * configuration. */ children?: Routes; /** * An object specifying lazy-loaded child routes. */ loadChildren?: LoadChildren; /** * A policy for when to run guards and resolvers on a route. * * Guards and/or resolvers will always run when a route is activated or deactivated. When a route * is unchanged, the default behavior is the same as `paramsChange`. * * `paramsChange` : Rerun the guards and resolvers when path or * path param changes. This does not include query parameters. This option is the default. * - `always` : Run on every execution. * - `pathParamsChange` : Rerun guards and resolvers when the path params * change. This does not compare matrix or query parameters. * - `paramsOrQueryParamsChange` : Run when path, matrix, or query parameters change. * - `pathParamsOrQueryParamsChange` : Rerun guards and resolvers when the path params * change or query params have changed. This does not include matrix parameters. * * @see {@link RunGuardsAndResolvers} */ runGuardsAndResolvers?: RunGuardsAndResolvers; /** * A `Provider` array to use for this `Route` and its `children`. * * The `Router` will create a new `EnvironmentInjector` for this * `Route` and use it for this `Route` and its `children`. If this * route also has a `loadChildren` function which returns an `NgModuleRef`, this injector will be * used as the parent of the lazy loaded module. */ providers?: Array<Provider | EnvironmentProviders>; } interface LoadedRouterConfig { routes: Route[]; injector: EnvironmentInjector | undefined; } /** * @description * * Interface that a class can implement to be a guard deciding if a route can be activated. * If all guards return `true`, navigation continues. If any guard returns `false`, * navigation is cancelled. If any guard returns a `UrlTree`, the current navigation * is cancelled and a new navigation begins to the `UrlTree` returned from the guard. * * The following example implements a `CanActivate` function that checks whether the * current user has permission to activate the requested route. * * ```ts * class UserToken {} * class Permissions { * canActivate(): boolean { * return true; * } * } * * @Injectable() * class CanActivateTeam implements CanActivate { * constructor(private permissions: Permissions, private currentUser: UserToken) {} * * canActivate( * route: ActivatedRouteSnapshot, * state: RouterStateSnapshot * ): MaybeAsync<GuardResult> { * return this.permissions.canActivate(this.currentUser, route.params.id); * } * } * ``` * * Here, the defined guard function is provided as part of the `Route` object * in the router configuration: * * ```ts * @NgModule({ * imports: [ * RouterModule.forRoot([ * { * path: 'team/:id', * component: TeamComponent, * canActivate: [CanActivateTeam] * } * ]) * ], * providers: [CanActivateTeam, UserToken, Permissions] * }) * class AppModule {} * ``` * * @publicApi */ interface CanActivate { canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): MaybeAsync<GuardResult>; } /** * The signature of a function used as a `canActivate` guard on a `Route`. * * If all guards return `true`, navigation continues. If any guard returns `false`, * navigation is cancelled. If any guard returns a `UrlTree`, the current navigation * is cancelled and a new navigation begins to the `UrlTree` returned from the guard. * * The following example implements and uses a `CanActivateFn` that checks whether the * current user has permission to activate the requested route. * * ```ts * @Injectable() * class UserToken {} * * @Injectable() * class PermissionsService { * canActivate(currentUser: UserToken, userId: string): boolean { * return true; * } * canMatch(currentUser: UserToken): boolean { * return true; * } * } * * const canActivateTeam: CanActivateFn = ( * route: ActivatedRouteSnapshot, * state: RouterStateSnapshot, * ) => { * return inject(PermissionsService).canActivate(inject(UserToken), route.params['id']); * }; * ``` * * Here, the defined guard function is provided as part of the `Route` object * in the router configuration: * * ```ts * bootstrapApplication(App, { * providers: [ * provideRouter([ * { * path: 'team/:id', * component: TeamComponent, * canActivate: [canActivateTeam], * }, * ]), * ], * }); * ``` * * @publicApi * @see {@link Route} */ type CanActivateFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => MaybeAsync<GuardResult>; /** * @description * * Interface that a class can implement to be a guard deciding if a child route can be activated. * If all guards return `true`, navigation continues. If any guard returns `false`, * navigation is cancelled. If any guard returns a `UrlTree`, current navigation * is cancelled and a new navigation begins to the `UrlTree` returned from the guard. * * The following example implements a `CanActivateChild` function that checks whether the * current user has permission to activate the requested child route. * * ```ts * class UserToken {} * class Permissions { * canActivate(user: UserToken, id: string): boolean { * return true; * } * } * * @Injectable() * class CanActivateTeam implements CanActivateChild { * constructor(private permissions: Permissions, private currentUser: UserToken) {} * * canActivateChild( * route: ActivatedRouteSnapshot, * state: RouterStateSnapshot * ): MaybeAsync<GuardResult> { * return this.permissions.canActivate(this.currentUser, route.params.id); * } * } * ``` * * Here, the defined guard function is provided as part of the `Route` object * in the router configuration: * * ```ts * @NgModule({ * imports: [ * RouterModule.forRoot([ * { * path: 'root', * canActivateChild: [CanActivateTeam], * children: [ * { * path: 'team/:id', * component: TeamComponent * } * ] * } * ]) * ], * providers: [CanActivateTeam, UserToken, Permissions] * }) * class AppModule {} * ``` * * @publicApi */ interface CanActivateChild { canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): MaybeAsync<GuardResult>; } /** * The signature of a function used as a `canActivateChild` guard on a `Route`. * * If all guards return `true`, navigation continues. If any guard returns `false`, * navigation is cancelled. If any guard returns a `UrlTree`, the current navigation * is cancelled and a new navigation begins to the `UrlTree` returned from the guard. * * The following example implements a `canActivate` function that checks whether the * current user has permission to activate the requested route. * * {@example router/route_functional_guards.ts region="CanActivateChildFn"} * * @publicApi * @see {@link Route} */ type CanActivateChildFn = (childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot) => MaybeAsync<GuardResult>; /** * @description * * Interface that a class can implement to be a guard deciding if a route can be deactivated. * If all guards return `true`, navigation continues. If any guard returns `false`, * navigation is cancelled. If any guard returns a `UrlTree`, current navigation * is cancelled and a new navigation begins to the `UrlTree` returned from the guard. * * The following example implements a `CanDeactivate` function that checks whether the * current user has permission to deactivate the requested route. * * ```ts * class UserToken {} * class Permissions { * canDeactivate(user: UserToken, id: string): boolean { * return true; * } * } * ``` * * Here, the defined guard function is provided as part of the `Route` object * in the router configuration: * * ```ts * @Injectable() * class CanDeactivateTeam implements CanDeactivate<TeamComponent> { * constructor(private permissions: Permissions, private currentUser: UserToken) {} * * canDeactivate( * component: TeamComponent, * currentRoute: ActivatedRouteSnapshot, * currentState: RouterStateSnapshot, * nextState: RouterStateSnapshot * ): MaybeAsync<GuardResult> { * return this.permissions.canDeactivate(this.currentUser, route.params.id); * } * } * * @NgModule({ * imports: [ * RouterModule.forRoot([ * { * path: 'team/:id', * component: TeamComponent, * canDeactivate: [CanDeactivateTeam] * } * ]) * ], * providers: [CanDeactivateTeam, UserToken, Permissions] * }) * class AppModule {} * ``` * * @publicApi */ interface CanDeactivate<T> { canDeactivate(component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot): MaybeAsync<GuardResult>; } /** * The signature of a function used as a `canDeactivate` guard on a `Route`. * * If all guards return `true`, navigation continues. If any guard returns `false`, * navigation is cancelled. If any guard returns a `UrlTree`, the current navigation * is cancelled and a new navigation begins to the `UrlTree` returned from the guard. * * The following example implements and uses a `CanDeactivateFn` that checks whether the * user component has unsaved changes before navigating away from the route. * * {@example router/route_functional_guards.ts region="CanDeactivateFn"} * * @publicApi * @see {@link Route} */ type CanDeactivateFn<T> = (component: T, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState: RouterStateSnapshot) => MaybeAsync<GuardResult>; /** * @description * * Interface that a class can implement to be a guard deciding if a `Route` can be matched. * If all guards return `true`, navigation continues and the `Router` will use the `Route` during * activation. If any guard returns `false`, the `Route` is skipped for matching and other `Route` * configurations are processed instead. * * The following example implements a `CanMatch` function that decides whether the * current user has permission to access the users page. * * * ```ts * class UserToken {} * class Permissions { * canAccess(user: UserToken, route: Route, segments: UrlSegment[]): boolean { * return true; * } * } * * @Injectable() * class CanMatchTeamSection implements CanMatch { * constructor(private permissions: Permissions, private currentUser: UserToken) {} * * canMatch(route: Route, segments: UrlSegment[]): Observable<boolean>|Promise<boolean>|boolean { * return this.permissions.canAccess(this.currentUser, route, segments); * } * } * ``` * * Here, the defined guard function is provided as part of the `Route` object * in the router configuration: * * ```ts * @NgModule({ * imports: [ * RouterModule.forRoot([ * { * path: 'team/:id', * component: TeamComponent, * loadChildren: () => import('./team').then(mod => mod.TeamModule), * canMatch: [CanMatchTeamSection] * }, * { * path: '**', * component: NotFoundComponent * } * ]) * ], * providers: [CanMatchTeamSection, UserToken, Permissions] * }) * class AppModule {} * ``` * * If the `CanMatchTeamSection` were to return `false`, the router would continue navigating to the * `team/:id` URL, but would load the `NotFoundComponent` because the `Route` for `'team/:id'` * could not be used for a URL match but the catch-all `**` `Route` did instead. * * @publicApi */ interface CanMatch { canMatch(route: Route, segments: UrlSegment[]): MaybeAsync<GuardResult>; } /** * The signature of a function used as a `canMatch` guard on a `Route`. * * If all guards return `true`, navigation continues and the `Router` will use the `Route` during * activation. If any guard returns `false`, the `Route` is skipped for matching and other `Route` * configurations are processed instead. * * The following example implements and uses a `CanMatchFn` that checks whether the * current user has permission to access the team page. * * {@example router/route_functional_guards.ts region="CanMatchFn"} * * @param route The route configuration. * @param segments The URL segments that have not been consumed by previous parent route evaluations. * * @publicApi * @see {@link Route} */ type CanMatchFn = (route: Route, segments: UrlSegment[]) => MaybeAsync<GuardResult>; /** * @description * * Interface that classes can implement to be a data provider. * A data provider class can be used with the router to resolve data during navigation. * The interface defines a `resolve()` method that is invoked right after the `ResolveStart` * router event. The router waits for the data to be resolved before the route is finally activated. * * The following example implements a `resolve()` method that retrieves the data * needed to activate the requested route. * * ```ts * @Injectable({ providedIn: 'root' }) * export class HeroResolver implements Resolve<Hero> { * constructor(private service: HeroService) {} * * resolve( * route: ActivatedRouteSnapshot, * state: RouterStateSnapshot * ): Observable<Hero>|Promise<Hero>|Hero { * return this.service.getHero(route.paramMap.get('id')); * } * } * ``` * * Here, the defined `resolve()` function is provided as part of the `Route` object * in the router configuration: * * ```ts * @NgModule({ * imports: [ * RouterModule.forRoot([ * { * path: 'detail/:id', * component: HeroDetailComponent, * resolve: { * hero: HeroResolver * } * } * ]) * ], * exports: [RouterModule] * }) * export class AppRoutingModule {} * ``` * * And you can access to your resolved data from `HeroComponent`: * * ```ts * @Component({ * selector: "app-hero", * templateUrl: "hero.component.html", * }) * export class HeroComponent { * * constructor(private activatedRoute: ActivatedRoute) {} * * ngOnInit() { * this.activatedRoute.data.subscribe(({ hero }) => { * // do something with your resolved data ... * }) * } * * } * ``` * * @usageNotes * * When both guard and resolvers are specified, the resolvers are not executed until * all guards have run and succeeded. * For example, consider the following route configuration: * * ```ts * { * path: 'base' * canActivate: [BaseGuard], * resolve: {data: BaseDataResolver} * children: [ * { * path: 'child', * guards: [ChildGuard], * component: ChildComponent, * resolve: {childData: ChildDataResolver} * } * ] * } * ``` * The order of execution is: BaseGuard, ChildGuard, BaseDataResolver, ChildDataResolver. * * @publicApi * @see {@link ResolveFn} */ interface Resolve<T> { resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): MaybeAsync<T | RedirectCommand>; } /** * Function type definition for a data provider. * * A data provider can be used with the router to resolve data during navigation. * The router waits for the data to be resolved before the route is finally activated. * * A resolver can also redirect a `RedirectCommand` and the Angular router will use * it to redirect the current navigation to the new destination. * * @usageNotes * * The following example implements a function that retrieves the data * needed to activate the requested route. * * ```ts * interface Hero { * name: string; * } * @Injectable() * export class HeroService { * getHero(id: string) { * return {name: `Superman-${id}`}; * } * } * * export const heroResolver: ResolveFn<Hero> = ( * route: ActivatedRouteSnapshot, * state: RouterStateSnapshot, * ) => { * return inject(HeroService).getHero(route.paramMap.get('id')!); * }; * * bootstrapApplication(App, { * providers: [ * provideRouter([ * { * path: 'detail/:id', * component: HeroDetailComponent, * resolve: {hero: heroResolver}, * }, * ]), * ], * }); * ``` * * And you can access to your resolved data from `HeroComponent`: * * ```ts * @Component({template: ''}) * export class HeroDetailComponent { * private activatedRoute = inject(ActivatedRoute); * * ngOnInit() { * this.activatedRoute.data.subscribe(({hero}) => { * // do something with your resolved data ... * }); * } * } * ``` * * If resolved data cannot be retrieved, you may want to redirect the user * to a new page instead: * * ```ts * export const heroResolver: ResolveFn<Hero> = async ( * route: ActivatedRouteSnapshot, * state: RouterStateSnapshot, * ) => { * const router = inject(Router); * const heroService = inject(HeroService); * try { * return await heroService.getHero(route.paramMap.get('id')!); * } catch { * return new RedirectCommand(router.parseUrl('/404')); * } * }; * ``` * * When both guard and resolvers are specified, the resolvers are not executed until * all guards have run and succeeded. * For example, consider the following route configuration: * * ```ts * { * path