UNPKG

@angular/router

Version:
1,202 lines (1,191 loc) 37 kB
/** * @license Angular v21.0.3 * (c) 2010-2025 Google LLC. https://angular.dev/ * License: MIT */ import * as i3 from '@angular/common'; import { PlatformNavigation, Location, ɵNavigationAdapterForLocation as _NavigationAdapterForLocation, LOCATION_INITIALIZED, ViewportScroller, LocationStrategy, HashLocationStrategy, PathLocationStrategy } from '@angular/common'; import * as i0 from '@angular/core'; import { signal, untracked, inject, ɵINTERNAL_APPLICATION_ERROR_HANDLER as _INTERNAL_APPLICATION_ERROR_HANDLER, HostAttributeToken, ɵRuntimeError as _RuntimeError, booleanAttribute, Directive, Attribute, HostBinding, Input, HostListener, EventEmitter, ContentChildren, Output, Injectable, createEnvironmentInjector, InjectionToken, ɵpublishExternalGlobalUtil as _publishExternalGlobalUtil, makeEnvironmentProviders, APP_BOOTSTRAP_LISTENER, provideEnvironmentInitializer, Injector, ApplicationRef, ɵIS_ENABLED_BLOCKING_INITIAL_NAVIGATION as _IS_ENABLED_BLOCKING_INITIAL_NAVIGATION, provideAppInitializer, ɵperformanceMarkFeature as _performanceMarkFeature, ENVIRONMENT_INITIALIZER, NgZone, NgModule } from '@angular/core'; import { ROUTER_CONFIGURATION, NavigationEnd, isUrlTree, Router, ActivatedRoute, RouterConfigLoader, IMPERATIVE_NAVIGATION, NavigationStart, NavigationSkipped, NavigationSkippedCode, Scroll, UrlSerializer, NavigationTransitions, HistoryStateManager, ROUTES, afterNextNavigation, StateManager, stringifyEvent, NAVIGATION_ERROR_HANDLER, RoutedComponentInputBinder, INPUT_BINDER, CREATE_VIEW_TRANSITION, createViewTransition, VIEW_TRANSITION_OPTIONS, DefaultUrlSerializer, ChildrenOutletContexts, RouterOutlet, ɵEmptyOutletComponent as _EmptyOutletComponent } from './_router-chunk.mjs'; import { Subject, of, from } from 'rxjs'; import { mergeAll, catchError, filter, concatMap, mergeMap } from 'rxjs/operators'; class RouterLink { router; route; tabIndexAttribute; renderer; el; locationStrategy; reactiveHref = signal(null, ...(ngDevMode ? [{ debugName: "reactiveHref" }] : [])); get href() { return untracked(this.reactiveHref); } set href(value) { this.reactiveHref.set(value); } target; queryParams; fragment; queryParamsHandling; state; info; relativeTo; isAnchorElement; subscription; onChanges = new Subject(); applicationErrorHandler = inject(_INTERNAL_APPLICATION_ERROR_HANDLER); options = inject(ROUTER_CONFIGURATION, { optional: true }); constructor(router, route, tabIndexAttribute, renderer, el, locationStrategy) { this.router = router; this.route = route; this.tabIndexAttribute = tabIndexAttribute; this.renderer = renderer; this.el = el; this.locationStrategy = locationStrategy; this.reactiveHref.set(inject(new HostAttributeToken('href'), { optional: true })); const tagName = el.nativeElement.tagName?.toLowerCase(); this.isAnchorElement = tagName === 'a' || tagName === 'area' || !!(typeof customElements === 'object' && customElements.get(tagName)?.observedAttributes?.includes?.('href')); if (!this.isAnchorElement) { this.subscribeToNavigationEventsIfNecessary(); } else { this.setTabIndexIfNotOnNativeEl('0'); } } subscribeToNavigationEventsIfNecessary() { if (this.subscription !== undefined || !this.isAnchorElement) { return; } let createSubcription = this.preserveFragment; const dependsOnRouterState = handling => handling === 'merge' || handling === 'preserve'; createSubcription ||= dependsOnRouterState(this.queryParamsHandling); createSubcription ||= !this.queryParamsHandling && !dependsOnRouterState(this.options?.defaultQueryParamsHandling); if (!createSubcription) { return; } this.subscription = this.router.events.subscribe(s => { if (s instanceof NavigationEnd) { this.updateHref(); } }); } preserveFragment = false; skipLocationChange = false; replaceUrl = false; setTabIndexIfNotOnNativeEl(newTabIndex) { if (this.tabIndexAttribute != null || this.isAnchorElement) { return; } this.applyAttributeValue('tabindex', newTabIndex); } ngOnChanges(changes) { if (ngDevMode && isUrlTree(this.routerLinkInput) && (this.fragment !== undefined || this.queryParams || this.queryParamsHandling || this.preserveFragment || this.relativeTo)) { throw new _RuntimeError(4017, 'Cannot configure queryParams or fragment when using a UrlTree as the routerLink input value.'); } if (this.isAnchorElement) { this.updateHref(); this.subscribeToNavigationEventsIfNecessary(); } this.onChanges.next(this); } routerLinkInput = null; set routerLink(commandsOrUrlTree) { if (commandsOrUrlTree == null) { this.routerLinkInput = null; this.setTabIndexIfNotOnNativeEl(null); } else { if (isUrlTree(commandsOrUrlTree)) { this.routerLinkInput = commandsOrUrlTree; } else { this.routerLinkInput = Array.isArray(commandsOrUrlTree) ? commandsOrUrlTree : [commandsOrUrlTree]; } this.setTabIndexIfNotOnNativeEl('0'); } } onClick(button, ctrlKey, shiftKey, altKey, metaKey) { const urlTree = this.urlTree; if (urlTree === null) { return true; } if (this.isAnchorElement) { if (button !== 0 || ctrlKey || shiftKey || altKey || metaKey) { return true; } if (typeof this.target === 'string' && this.target != '_self') { return true; } } const extras = { skipLocationChange: this.skipLocationChange, replaceUrl: this.replaceUrl, state: this.state, info: this.info }; this.router.navigateByUrl(urlTree, extras)?.catch(e => { this.applicationErrorHandler(e); }); return !this.isAnchorElement; } ngOnDestroy() { this.subscription?.unsubscribe(); } updateHref() { const urlTree = this.urlTree; this.reactiveHref.set(urlTree !== null && this.locationStrategy ? this.locationStrategy?.prepareExternalUrl(this.router.serializeUrl(urlTree)) ?? '' : null); } applyAttributeValue(attrName, attrValue) { const renderer = this.renderer; const nativeElement = this.el.nativeElement; if (attrValue !== null) { renderer.setAttribute(nativeElement, attrName, attrValue); } else { renderer.removeAttribute(nativeElement, attrName); } } get urlTree() { if (this.routerLinkInput === null) { return null; } else if (isUrlTree(this.routerLinkInput)) { return this.routerLinkInput; } return this.router.createUrlTree(this.routerLinkInput, { relativeTo: this.relativeTo !== undefined ? this.relativeTo : this.route, queryParams: this.queryParams, fragment: this.fragment, queryParamsHandling: this.queryParamsHandling, preserveFragment: this.preserveFragment }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: RouterLink, deps: [{ token: Router }, { token: ActivatedRoute }, { token: 'tabindex', attribute: true }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i3.LocationStrategy }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.0.3", type: RouterLink, isStandalone: true, selector: "[routerLink]", inputs: { target: "target", queryParams: "queryParams", fragment: "fragment", queryParamsHandling: "queryParamsHandling", state: "state", info: "info", relativeTo: "relativeTo", preserveFragment: ["preserveFragment", "preserveFragment", booleanAttribute], skipLocationChange: ["skipLocationChange", "skipLocationChange", booleanAttribute], replaceUrl: ["replaceUrl", "replaceUrl", booleanAttribute], routerLink: "routerLink" }, host: { listeners: { "click": "onClick($event.button,$event.ctrlKey,$event.shiftKey,$event.altKey,$event.metaKey)" }, properties: { "attr.href": "reactiveHref()", "attr.target": "this.target" } }, usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: RouterLink, decorators: [{ type: Directive, args: [{ selector: '[routerLink]', host: { '[attr.href]': 'reactiveHref()' } }] }], ctorParameters: () => [{ type: Router }, { type: ActivatedRoute }, { type: undefined, decorators: [{ type: Attribute, args: ['tabindex'] }] }, { type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i3.LocationStrategy }], propDecorators: { target: [{ type: HostBinding, args: ['attr.target'] }, { type: Input }], queryParams: [{ type: Input }], fragment: [{ type: Input }], queryParamsHandling: [{ type: Input }], state: [{ type: Input }], info: [{ type: Input }], relativeTo: [{ type: Input }], preserveFragment: [{ type: Input, args: [{ transform: booleanAttribute }] }], skipLocationChange: [{ type: Input, args: [{ transform: booleanAttribute }] }], replaceUrl: [{ type: Input, args: [{ transform: booleanAttribute }] }], routerLink: [{ type: Input }], onClick: [{ type: HostListener, args: ['click', ['$event.button', '$event.ctrlKey', '$event.shiftKey', '$event.altKey', '$event.metaKey']] }] } }); class RouterLinkActive { router; element; renderer; cdr; links; classes = []; routerEventsSubscription; linkInputChangesSubscription; _isActive = false; get isActive() { return this._isActive; } routerLinkActiveOptions = { exact: false }; ariaCurrentWhenActive; isActiveChange = new EventEmitter(); link = inject(RouterLink, { optional: true }); constructor(router, element, renderer, cdr) { this.router = router; this.element = element; this.renderer = renderer; this.cdr = cdr; this.routerEventsSubscription = router.events.subscribe(s => { if (s instanceof NavigationEnd) { this.update(); } }); } ngAfterContentInit() { of(this.links.changes, of(null)).pipe(mergeAll()).subscribe(_ => { this.update(); this.subscribeToEachLinkOnChanges(); }); } subscribeToEachLinkOnChanges() { this.linkInputChangesSubscription?.unsubscribe(); const allLinkChanges = [...this.links.toArray(), this.link].filter(link => !!link).map(link => link.onChanges); this.linkInputChangesSubscription = from(allLinkChanges).pipe(mergeAll()).subscribe(link => { if (this._isActive !== this.isLinkActive(this.router)(link)) { this.update(); } }); } set routerLinkActive(data) { const classes = Array.isArray(data) ? data : data.split(' '); this.classes = classes.filter(c => !!c); } ngOnChanges(changes) { this.update(); } ngOnDestroy() { this.routerEventsSubscription.unsubscribe(); this.linkInputChangesSubscription?.unsubscribe(); } update() { if (!this.links || !this.router.navigated) return; queueMicrotask(() => { const hasActiveLinks = this.hasActiveLinks(); this.classes.forEach(c => { if (hasActiveLinks) { this.renderer.addClass(this.element.nativeElement, c); } else { this.renderer.removeClass(this.element.nativeElement, c); } }); if (hasActiveLinks && this.ariaCurrentWhenActive !== undefined) { this.renderer.setAttribute(this.element.nativeElement, 'aria-current', this.ariaCurrentWhenActive.toString()); } else { this.renderer.removeAttribute(this.element.nativeElement, 'aria-current'); } if (this._isActive !== hasActiveLinks) { this._isActive = hasActiveLinks; this.cdr.markForCheck(); this.isActiveChange.emit(hasActiveLinks); } }); } isLinkActive(router) { const options = isActiveMatchOptions(this.routerLinkActiveOptions) ? this.routerLinkActiveOptions : this.routerLinkActiveOptions.exact || false; return link => { const urlTree = link.urlTree; return urlTree ? router.isActive(urlTree, options) : false; }; } hasActiveLinks() { const isActiveCheckFn = this.isLinkActive(this.router); return this.link && isActiveCheckFn(this.link) || this.links.some(isActiveCheckFn); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: RouterLinkActive, deps: [{ token: Router }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.0.3", type: RouterLinkActive, isStandalone: true, selector: "[routerLinkActive]", inputs: { routerLinkActiveOptions: "routerLinkActiveOptions", ariaCurrentWhenActive: "ariaCurrentWhenActive", routerLinkActive: "routerLinkActive" }, outputs: { isActiveChange: "isActiveChange" }, queries: [{ propertyName: "links", predicate: RouterLink, descendants: true }], exportAs: ["routerLinkActive"], usesOnChanges: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: RouterLinkActive, decorators: [{ type: Directive, args: [{ selector: '[routerLinkActive]', exportAs: 'routerLinkActive' }] }], ctorParameters: () => [{ type: Router }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }], propDecorators: { links: [{ type: ContentChildren, args: [RouterLink, { descendants: true }] }], routerLinkActiveOptions: [{ type: Input }], ariaCurrentWhenActive: [{ type: Input }], isActiveChange: [{ type: Output }], routerLinkActive: [{ type: Input }] } }); function isActiveMatchOptions(options) { return !!options.paths; } class PreloadingStrategy {} class PreloadAllModules { preload(route, fn) { return fn().pipe(catchError(() => of(null))); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: PreloadAllModules, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: PreloadAllModules, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: PreloadAllModules, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); class NoPreloading { preload(route, fn) { return of(null); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NoPreloading, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NoPreloading, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NoPreloading, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); class RouterPreloader { router; injector; preloadingStrategy; loader; subscription; constructor(router, injector, preloadingStrategy, loader) { this.router = router; this.injector = injector; this.preloadingStrategy = preloadingStrategy; this.loader = loader; } setUpPreloading() { this.subscription = this.router.events.pipe(filter(e => e instanceof NavigationEnd), concatMap(() => this.preload())).subscribe(() => {}); } preload() { return this.processRoutes(this.injector, this.router.config); } ngOnDestroy() { if (this.subscription) { this.subscription.unsubscribe(); } } processRoutes(injector, routes) { const res = []; for (const route of routes) { if (route.providers && !route._injector) { route._injector = createEnvironmentInjector(route.providers, injector, `Route: ${route.path}`); } const injectorForCurrentRoute = route._injector ?? injector; const injectorForChildren = route._loadedInjector ?? injectorForCurrentRoute; if (route.loadChildren && !route._loadedRoutes && route.canLoad === undefined || route.loadComponent && !route._loadedComponent) { res.push(this.preloadConfig(injectorForCurrentRoute, route)); } if (route.children || route._loadedRoutes) { res.push(this.processRoutes(injectorForChildren, route.children ?? route._loadedRoutes)); } } return from(res).pipe(mergeAll()); } preloadConfig(injector, route) { return this.preloadingStrategy.preload(route, () => { let loadedChildren$; if (route.loadChildren && route.canLoad === undefined) { loadedChildren$ = from(this.loader.loadChildren(injector, route)); } else { loadedChildren$ = of(null); } const recursiveLoadChildren$ = loadedChildren$.pipe(mergeMap(config => { if (config === null) { return of(void 0); } route._loadedRoutes = config.routes; route._loadedInjector = config.injector; return this.processRoutes(config.injector ?? injector, config.routes); })); if (route.loadComponent && !route._loadedComponent) { const loadComponent$ = this.loader.loadComponent(injector, route); return from([recursiveLoadChildren$, loadComponent$]).pipe(mergeAll()); } else { return recursiveLoadChildren$; } }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: RouterPreloader, deps: [{ token: Router }, { token: i0.EnvironmentInjector }, { token: PreloadingStrategy }, { token: RouterConfigLoader }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: RouterPreloader, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: RouterPreloader, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: Router }, { type: i0.EnvironmentInjector }, { type: PreloadingStrategy }, { type: RouterConfigLoader }] }); const ROUTER_SCROLLER = new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'Router Scroller' : ''); class RouterScroller { urlSerializer; transitions; viewportScroller; zone; options; routerEventsSubscription; scrollEventsSubscription; lastId = 0; lastSource = IMPERATIVE_NAVIGATION; restoredId = 0; store = {}; constructor(urlSerializer, transitions, viewportScroller, zone, options = {}) { this.urlSerializer = urlSerializer; this.transitions = transitions; this.viewportScroller = viewportScroller; this.zone = zone; this.options = options; options.scrollPositionRestoration ||= 'disabled'; options.anchorScrolling ||= 'disabled'; } init() { if (this.options.scrollPositionRestoration !== 'disabled') { this.viewportScroller.setHistoryScrollRestoration('manual'); } this.routerEventsSubscription = this.createScrollEvents(); this.scrollEventsSubscription = this.consumeScrollEvents(); } createScrollEvents() { return this.transitions.events.subscribe(e => { if (e instanceof NavigationStart) { this.store[this.lastId] = this.viewportScroller.getScrollPosition(); this.lastSource = e.navigationTrigger; this.restoredId = e.restoredState ? e.restoredState.navigationId : 0; } else if (e instanceof NavigationEnd) { this.lastId = e.id; this.scheduleScrollEvent(e, this.urlSerializer.parse(e.urlAfterRedirects).fragment); } else if (e instanceof NavigationSkipped && e.code === NavigationSkippedCode.IgnoredSameUrlNavigation) { this.lastSource = undefined; this.restoredId = 0; this.scheduleScrollEvent(e, this.urlSerializer.parse(e.url).fragment); } }); } consumeScrollEvents() { return this.transitions.events.subscribe(e => { if (!(e instanceof Scroll)) return; const instantScroll = { behavior: 'instant' }; if (e.position) { if (this.options.scrollPositionRestoration === 'top') { this.viewportScroller.scrollToPosition([0, 0], instantScroll); } else if (this.options.scrollPositionRestoration === 'enabled') { this.viewportScroller.scrollToPosition(e.position, instantScroll); } } else { if (e.anchor && this.options.anchorScrolling === 'enabled') { this.viewportScroller.scrollToAnchor(e.anchor); } else if (this.options.scrollPositionRestoration !== 'disabled') { this.viewportScroller.scrollToPosition([0, 0]); } } }); } scheduleScrollEvent(routerEvent, anchor) { this.zone.runOutsideAngular(async () => { await new Promise(resolve => { setTimeout(resolve); if (typeof requestAnimationFrame !== 'undefined') { requestAnimationFrame(resolve); } }); this.zone.run(() => { this.transitions.events.next(new Scroll(routerEvent, this.lastSource === 'popstate' ? this.store[this.restoredId] : null, anchor)); }); }); } ngOnDestroy() { this.routerEventsSubscription?.unsubscribe(); this.scrollEventsSubscription?.unsubscribe(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: RouterScroller, deps: "invalid", target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: RouterScroller }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: RouterScroller, decorators: [{ type: Injectable }], ctorParameters: () => [{ type: UrlSerializer }, { type: NavigationTransitions }, { type: i3.ViewportScroller }, { type: i0.NgZone }, { type: undefined }] }); function getLoadedRoutes(route) { return route._loadedRoutes; } function getRouterInstance(injector) { return injector.get(Router, null, { optional: true }); } function navigateByUrl(router, url) { if (!(router instanceof Router)) { throw new Error('The provided router is not an Angular Router.'); } return router.navigateByUrl(url); } class NavigationStateManager extends HistoryStateManager { navigation = inject(PlatformNavigation); registerNonRouterCurrentEntryChangeListener(listener) { return this.location.subscribe(event => { if (event['type'] === 'popstate') { const state = this.navigation.currentEntry?.getState(); listener(event['url'], state, 'popstate'); } }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NavigationStateManager, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NavigationStateManager, providedIn: 'root' }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: NavigationStateManager, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); function provideRouter(routes, ...features) { if (typeof ngDevMode === 'undefined' || ngDevMode) { _publishExternalGlobalUtil('ɵgetLoadedRoutes', getLoadedRoutes); _publishExternalGlobalUtil('ɵgetRouterInstance', getRouterInstance); _publishExternalGlobalUtil('ɵnavigateByUrl', navigateByUrl); } return makeEnvironmentProviders([{ provide: ROUTES, multi: true, useValue: routes }, typeof ngDevMode === 'undefined' || ngDevMode ? { provide: ROUTER_IS_PROVIDED, useValue: true } : [], { provide: ActivatedRoute, useFactory: rootRoute }, { provide: APP_BOOTSTRAP_LISTENER, multi: true, useFactory: getBootstrapListener }, features.map(feature => feature.ɵproviders)]); } function rootRoute() { return inject(Router).routerState.root; } function routerFeature(kind, providers) { return { ɵkind: kind, ɵproviders: providers }; } const ROUTER_IS_PROVIDED = new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'Router is provided' : '', { 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.'); } }; } }; function provideRoutes(routes) { return [{ provide: ROUTES, multi: true, useValue: routes }, typeof ngDevMode === 'undefined' || ngDevMode ? routerIsProvidedDevModeCheck : []]; } function withInMemoryScrolling(options = {}) { const providers = [{ provide: ROUTER_SCROLLER, useFactory: () => { const viewportScroller = inject(ViewportScroller); const zone = inject(NgZone); const transitions = inject(NavigationTransitions); const urlSerializer = inject(UrlSerializer); return new RouterScroller(urlSerializer, transitions, viewportScroller, zone, options); } }]; return routerFeature(4, providers); } function withPlatformNavigation() { const devModeLocationCheck = typeof ngDevMode === 'undefined' || ngDevMode ? [provideEnvironmentInitializer(() => { const locationInstance = inject(Location); if (!(locationInstance instanceof _NavigationAdapterForLocation)) { const locationConstructorName = locationInstance.constructor.name; let message = `'withPlatformNavigation' provides a 'Location' implementation that ensures navigation APIs are consistently used.` + ` An instance of ${locationConstructorName} was found instead.`; if (locationConstructorName === 'SpyLocation') { message += ` One of 'RouterTestingModule' or 'provideLocationMocks' was likely used. 'withPlatformNavigation' does not work with these because they override the Location implementation.`; } throw new Error(message); } })] : []; const providers = [{ provide: StateManager, useExisting: NavigationStateManager }, { provide: Location, useClass: _NavigationAdapterForLocation }, devModeLocationCheck]; return routerFeature(4, providers); } function getBootstrapListener() { const injector = inject(Injector); return bootstrappedComponentRef => { const ref = injector.get(ApplicationRef); if (bootstrappedComponentRef !== ref.components[0]) { return; } const router = injector.get(Router); const bootstrapDone = injector.get(BOOTSTRAP_DONE); if (injector.get(INITIAL_NAVIGATION) === 1) { router.initialNavigation(); } injector.get(ROUTER_PRELOADER, null, { optional: true })?.setUpPreloading(); injector.get(ROUTER_SCROLLER, null, { optional: true })?.init(); router.resetRootComponentType(ref.componentTypes[0]); if (!bootstrapDone.closed) { bootstrapDone.next(); bootstrapDone.complete(); bootstrapDone.unsubscribe(); } }; } const BOOTSTRAP_DONE = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'bootstrap done indicator' : '', { factory: () => { return new Subject(); } }); const INITIAL_NAVIGATION = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'initial navigation' : '', { factory: () => 1 }); function withEnabledBlockingInitialNavigation() { const providers = [{ provide: _IS_ENABLED_BLOCKING_INITIAL_NAVIGATION, useValue: true }, { provide: INITIAL_NAVIGATION, useValue: 0 }, provideAppInitializer(() => { const injector = inject(Injector); const locationInitialized = injector.get(LOCATION_INITIALIZED, Promise.resolve()); return locationInitialized.then(() => { return new Promise(resolve => { const router = injector.get(Router); const bootstrapDone = injector.get(BOOTSTRAP_DONE); afterNextNavigation(router, () => { resolve(true); }); injector.get(NavigationTransitions).afterPreactivation = () => { resolve(true); return bootstrapDone.closed ? of(void 0) : bootstrapDone; }; router.initialNavigation(); }); }); })]; return routerFeature(2, providers); } function withDisabledInitialNavigation() { const providers = [provideAppInitializer(() => { inject(Router).setUpLocationChangeListener(); }), { provide: INITIAL_NAVIGATION, useValue: 2 }]; return routerFeature(3, providers); } function withDebugTracing() { let providers = []; if (typeof ngDevMode === 'undefined' || ngDevMode) { providers = [{ provide: ENVIRONMENT_INITIALIZER, multi: true, useFactory: () => { const router = inject(Router); return () => router.events.subscribe(e => { console.group?.(`Router Event: ${e.constructor.name}`); console.log(stringifyEvent(e)); console.log(e); console.groupEnd?.(); }); } }]; } else { providers = []; } return routerFeature(1, providers); } const ROUTER_PRELOADER = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'router preloader' : ''); function withPreloading(preloadingStrategy) { const providers = [{ provide: ROUTER_PRELOADER, useExisting: RouterPreloader }, { provide: PreloadingStrategy, useExisting: preloadingStrategy }]; return routerFeature(0, providers); } function withRouterConfig(options) { const providers = [{ provide: ROUTER_CONFIGURATION, useValue: options }]; return routerFeature(5, providers); } function withHashLocation() { const providers = [{ provide: LocationStrategy, useClass: HashLocationStrategy }]; return routerFeature(6, providers); } function withNavigationErrorHandler(handler) { const providers = [{ provide: NAVIGATION_ERROR_HANDLER, useValue: handler }]; return routerFeature(7, providers); } function withComponentInputBinding() { const providers = [RoutedComponentInputBinder, { provide: INPUT_BINDER, useExisting: RoutedComponentInputBinder }]; return routerFeature(8, providers); } function withViewTransitions(options) { _performanceMarkFeature('NgRouterViewTransitions'); const providers = [{ provide: CREATE_VIEW_TRANSITION, useValue: createViewTransition }, { provide: VIEW_TRANSITION_OPTIONS, useValue: { skipNextTransition: !!options?.skipInitialTransition, ...options } }]; return routerFeature(9, providers); } const ROUTER_DIRECTIVES = [RouterOutlet, RouterLink, RouterLinkActive, _EmptyOutletComponent]; const ROUTER_FORROOT_GUARD = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'router duplicate forRoot guard' : ''); const ROUTER_PROVIDERS = [Location, { provide: UrlSerializer, useClass: DefaultUrlSerializer }, Router, ChildrenOutletContexts, { provide: ActivatedRoute, useFactory: rootRoute }, RouterConfigLoader, typeof ngDevMode === 'undefined' || ngDevMode ? { provide: ROUTER_IS_PROVIDED, useValue: true } : []]; class RouterModule { constructor() { if (typeof ngDevMode === 'undefined' || ngDevMode) { inject(ROUTER_FORROOT_GUARD, { optional: true }); } } static forRoot(routes, config) { return { ngModule: RouterModule, providers: [ROUTER_PROVIDERS, typeof ngDevMode === 'undefined' || ngDevMode ? config?.enableTracing ? withDebugTracing().ɵproviders : [] : [], { provide: ROUTES, multi: true, useValue: routes }, typeof ngDevMode === 'undefined' || ngDevMode ? { provide: ROUTER_FORROOT_GUARD, useFactory: provideForRootGuard } : [], config?.errorHandler ? { provide: NAVIGATION_ERROR_HANDLER, useValue: config.errorHandler } : [], { provide: ROUTER_CONFIGURATION, useValue: config ? config : {} }, config?.useHash ? provideHashLocationStrategy() : providePathLocationStrategy(), provideRouterScroller(), config?.preloadingStrategy ? withPreloading(config.preloadingStrategy).ɵproviders : [], config?.initialNavigation ? provideInitialNavigation(config) : [], config?.bindToComponentInputs ? withComponentInputBinding().ɵproviders : [], config?.enableViewTransitions ? withViewTransitions().ɵproviders : [], provideRouterInitializer()] }; } static forChild(routes) { return { ngModule: RouterModule, providers: [{ provide: ROUTES, multi: true, useValue: routes }] }; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: RouterModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.0.3", ngImport: i0, type: RouterModule, imports: [RouterOutlet, RouterLink, RouterLinkActive, _EmptyOutletComponent], exports: [RouterOutlet, RouterLink, RouterLinkActive, _EmptyOutletComponent] }); static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: RouterModule }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImport: i0, type: RouterModule, decorators: [{ type: NgModule, args: [{ imports: ROUTER_DIRECTIVES, exports: ROUTER_DIRECTIVES }] }], ctorParameters: () => [] }); function provideRouterScroller() { return { provide: ROUTER_SCROLLER, useFactory: () => { const viewportScroller = inject(ViewportScroller); const zone = inject(NgZone); const config = inject(ROUTER_CONFIGURATION); const transitions = inject(NavigationTransitions); const urlSerializer = inject(UrlSerializer); if (config.scrollOffset) { viewportScroller.setOffset(config.scrollOffset); } return new RouterScroller(urlSerializer, transitions, viewportScroller, zone, config); } }; } function provideHashLocationStrategy() { return { provide: LocationStrategy, useClass: HashLocationStrategy }; } function providePathLocationStrategy() { return { provide: LocationStrategy, useClass: PathLocationStrategy }; } function provideForRootGuard() { const router = inject(Router, { optional: true, skipSelf: true }); if (router) { throw new _RuntimeError(4007, `The Router was provided more than once. This can happen if 'forRoot' is used outside of the root injector.` + ` Lazy loaded modules should use RouterModule.forChild() instead.`); } return 'guarded'; } function provideInitialNavigation(config) { return [config.initialNavigation === 'disabled' ? withDisabledInitialNavigation().ɵproviders : [], config.initialNavigation === 'enabledBlocking' ? withEnabledBlockingInitialNavigation().ɵproviders : []]; } const ROUTER_INITIALIZER = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'Router Initializer' : ''); function provideRouterInitializer() { return [{ provide: ROUTER_INITIALIZER, useFactory: getBootstrapListener }, { provide: APP_BOOTSTRAP_LISTENER, multi: true, useExisting: ROUTER_INITIALIZER }]; } export { NoPreloading, PreloadAllModules, PreloadingStrategy, ROUTER_INITIALIZER, ROUTER_PROVIDERS, RouterLink, RouterLinkActive, RouterModule, RouterPreloader, provideRouter, provideRoutes, withComponentInputBinding, withDebugTracing, withDisabledInitialNavigation, withEnabledBlockingInitialNavigation, withHashLocation, withInMemoryScrolling, withNavigationErrorHandler, withPlatformNavigation, withPreloading, withRouterConfig, withViewTransitions }; //# sourceMappingURL=_router_module-chunk.mjs.map