Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitfe701d7

Browse files
committed
refactor(router): Change RouterLink internals to use signals
This simplifies some of the internals of RouterLink because signals dothe heavy lifting of determining when things have changed
1 parent789f91b commitfe701d7

File tree

5 files changed

+196
-173
lines changed

5 files changed

+196
-173
lines changed

‎packages/core/test/bundling/router/bundle.golden_symbols.json‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
"COMPLETE_NOTIFICATION",
4040
"COMPONENT_REGEX",
4141
"COMPONENT_VARIABLE",
42+
"COMPUTED_NODE",
43+
"COMPUTING",
4244
"CONTAINER_HEADER_OFFSET",
4345
"CONTENT_ATTR",
4446
"CONTEXT",
@@ -93,6 +95,7 @@
9395
"ENABLE_ROOT_COMPONENT_BOOTSTRAP",
9496
"ENVIRONMENT",
9597
"ENVIRONMENT_INITIALIZER",
98+
"ERRORED",
9699
"EVENT_MANAGER_PLUGINS",
97100
"EffectRefImpl",
98101
"EffectScheduler",
@@ -133,6 +136,7 @@
133136
"InputFlags",
134137
"ItemComponent",
135138
"KeyEventsPlugin",
139+
"LINKED_SIGNAL_NODE",
136140
"LOCALE_ID",
137141
"LOCALE_ID",
138142
"LQueries_",
@@ -300,6 +304,7 @@
300304
"TracingService",
301305
"Tree",
302306
"TreeNode",
307+
"UNSET",
303308
"USE_VALUE",
304309
"UnsubscriptionError",
305310
"UrlHandlingStrategy",
@@ -445,6 +450,7 @@
445450
"compare",
446451
"computeNavigation",
447452
"computeStaticStyling",
453+
"computed",
448454
"concat",
449455
"concatAll",
450456
"concatMap",
@@ -473,6 +479,7 @@
473479
"createAndRenderEmbeddedLView",
474480
"createChildrenForEmptyPaths",
475481
"createComponentLView",
482+
"createComputed",
476483
"createContainerRef",
477484
"createContentQuery",
478485
"createDirectivesInstances",
@@ -492,6 +499,7 @@
492499
"createLQuery",
493500
"createLView",
494501
"createLinkElement",
502+
"createLinkedSignal",
495503
"createLocation",
496504
"createNewSegmentChildren",
497505
"createNewSegmentGroup",
@@ -735,6 +743,7 @@
735743
"hasTagAndTypeMatch",
736744
"icuContainerIterate",
737745
"identity",
746+
"identityFn",
738747
"importProvidersFrom",
739748
"inNotificationPhase",
740749
"includeViewProviders",
@@ -857,6 +866,9 @@
857866
"leaveView",
858867
"leaveViewLight",
859868
"linkTNodeInTView",
869+
"linkedSignal",
870+
"linkedSignalSetFn",
871+
"linkedSignalUpdateFn",
860872
"listenToDomEvent",
861873
"listenToOutput",
862874
"listenerInternal",
@@ -1129,6 +1141,7 @@
11291141
"updateSegmentGroup",
11301142
"updateSegmentGroupChildren",
11311143
"updateTextNode",
1144+
"upgradeLinkedSignalGetter",
11321145
"validateCommands",
11331146
"viewAttachedToChangeDetector",
11341147
"viewAttachedToContainer",

‎packages/router/src/directives/router_link.ts‎

Lines changed: 95 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import {LocationStrategy} from '@angular/common';
1010
import{
1111
Attribute,
1212
booleanAttribute,
13+
computed,
1314
Directive,
15+
effect,
1416
ElementRef,
1517
HostAttributeToken,
16-
HostBinding,
1718
HostListener,
1819
inject,
1920
Input,
21+
linkedSignal,
2022
OnChanges,
2123
OnDestroy,
2224
Renderer2,
@@ -28,10 +30,8 @@ import {
2830
}from'@angular/core';
2931
import{Subject,Subscription}from'rxjs';
3032
import{RuntimeErrorCode}from'../errors';
31-
import{Event,NavigationEnd}from'../events';
3233
import{QueryParamsHandling}from'../models';
3334
import{Router}from'../router';
34-
import{ROUTER_CONFIGURATION}from'../router_config';
3535
import{ActivatedRoute}from'../router_state';
3636
import{Params}from'../shared';
3737
import{isUrlTree,UrlTree}from'../url_tree';
@@ -146,11 +146,23 @@ import {isUrlTree, UrlTree} from '../url_tree';
146146
selector:'[routerLink]',
147147
host:{
148148
'[attr.href]':'reactiveHref()',
149+
'[attr.target]':'_target()',
149150
},
150151
})
151152
exportclassRouterLinkimplementsOnChanges,OnDestroy{
152-
/**@nodoc */
153-
protectedreadonlyreactiveHref=signal<string|null>(null);
153+
privatehrefAttributeValue=inject(newHostAttributeToken('href'),{optional:true});
154+
/**@docs-private */
155+
protectedreadonlyreactiveHref=linkedSignal(()=>{
156+
if(!this.isAnchorElement){
157+
// Set the initial href value to whatever exists on the host element already
158+
returnthis.hrefAttributeValue;
159+
}
160+
161+
consturlTree=this._urlTree();
162+
returnurlTree!==null&&this.locationStrategy
163+
?(this.locationStrategy?.prepareExternalUrl(this.router.serializeUrl(urlTree))??'')
164+
:null;
165+
});
154166
/**
155167
* Represents an `href` attribute value applied to a host element,
156168
* when a host element is an `<a>`/`<area>` tag or a compatible custom element.
@@ -169,7 +181,13 @@ export class RouterLink implements OnChanges, OnDestroy {
169181
* This is only used when the host element is
170182
* an `<a>`/`<area>` tag or a compatible custom element.
171183
*/
172-
@HostBinding('attr.target') @Input()target?:string;
184+
@Input()target?:string;
185+
186+
/**@docs-private @internal */
187+
protected_target=computed(()=>{
188+
this.changes();// track input changes
189+
returnthis.target;
190+
});
173191

174192
/**
175193
* Passed to {@link Router#createUrlTree} as part of the
@@ -217,16 +235,38 @@ export class RouterLink implements OnChanges, OnDestroy {
217235
*/
218236
@Input()relativeTo?:ActivatedRoute|null;
219237

220-
/** Whether a host element is an `<a>`/`<area>` tag or a compatible custom element. */
221-
privateisAnchorElement:boolean;
238+
/**
239+
* Passed to {@link Router#createUrlTree} as part of the
240+
* `UrlCreationOptions`.
241+
*@see {@link UrlCreationOptions#preserveFragment}
242+
*@see {@link Router#createUrlTree}
243+
*/
244+
@Input({transform:booleanAttribute})preserveFragment:boolean=false;
222245

223-
privatesubscription?:Subscription;
246+
/**
247+
* Passed to {@link Router#navigateByUrl} as part of the
248+
* `NavigationBehaviorOptions`.
249+
*@see {@link NavigationBehaviorOptions#skipLocationChange}
250+
*@see {@link Router#navigateByUrl}
251+
*/
252+
@Input({transform:booleanAttribute})skipLocationChange:boolean=false;
224253

254+
/**
255+
* Passed to {@link Router#navigateByUrl} as part of the
256+
* `NavigationBehaviorOptions`.
257+
*@see {@link NavigationBehaviorOptions#replaceUrl}
258+
*@see {@link Router#navigateByUrl}
259+
*/
260+
@Input({transform:booleanAttribute})replaceUrl:boolean=false;
261+
262+
/** Whether a host element is an `<a>`/`<area>` tag or a compatible custom element. */
263+
privatereadonlyisAnchorElement:boolean;
264+
privatesubscription?:Subscription;
225265
/**@internal */
226266
onChanges=newSubject<RouterLink>();
227-
267+
// This is a hack around not having signal inputs.
268+
privatereadonlychanges=signal({});
228269
privatereadonlyapplicationErrorHandler=inject(ɵINTERNAL_APPLICATION_ERROR_HANDLER);
229-
privatereadonlyoptions=inject(ROUTER_CONFIGURATION,{optional:true});
230270

231271
constructor(
232272
privaterouter:Router,
@@ -236,8 +276,6 @@ export class RouterLink implements OnChanges, OnDestroy {
236276
privatereadonlyel:ElementRef,
237277
privatelocationStrategy?:LocationStrategy,
238278
){
239-
// Set the initial href value to whatever exists on the host element already
240-
this.reactiveHref.set(inject(newHostAttributeToken('href'),{optional:true}));
241279
consttagName=el.nativeElement.tagName?.toLowerCase();
242280
this.isAnchorElement=
243281
tagName==='a'||
@@ -254,61 +292,28 @@ export class RouterLink implements OnChanges, OnDestroy {
254292
)
255293
);
256294

257-
if(!this.isAnchorElement){
258-
this.subscribeToNavigationEventsIfNecessary();
259-
}else{
260-
this.setTabIndexIfNotOnNativeEl('0');
261-
}
262-
}
263-
264-
privatesubscribeToNavigationEventsIfNecessary(){
265-
if(this.subscription!==undefined||!this.isAnchorElement){
266-
return;
267-
}
295+
this.setTabIndexIfNotOnNativeEl('0');
268296

269-
// preserving fragment in router state
270-
letcreateSubcription=this.preserveFragment;
271-
// preserving or merging with query params in router state
272-
constdependsOnRouterState=(handling?:QueryParamsHandling|null)=>
273-
handling==='merge'||handling==='preserve';
274-
createSubcription||=dependsOnRouterState(this.queryParamsHandling);
275-
createSubcription||=
276-
!this.queryParamsHandling&&!dependsOnRouterState(this.options?.defaultQueryParamsHandling);
277-
if(!createSubcription){
278-
return;
297+
if(ngDevMode){
298+
effect(()=>{
299+
this.changes();// track input changes
300+
if(
301+
isUrlTree(this.routerLinkInput)&&
302+
(this.fragment!==undefined||
303+
this.queryParams||
304+
this.queryParamsHandling||
305+
this.preserveFragment||
306+
this.relativeTo)
307+
){
308+
thrownewRuntimeError(
309+
RuntimeErrorCode.INVALID_ROUTER_LINK_INPUTS,
310+
'Cannot configure queryParams or fragment when using a UrlTree as the routerLink input value.',
311+
);
312+
}
313+
});
279314
}
280-
281-
this.subscription=this.router.events.subscribe((s:Event)=>{
282-
if(sinstanceofNavigationEnd){
283-
this.updateHref();
284-
}
285-
});
286315
}
287316

288-
/**
289-
* Passed to {@link Router#createUrlTree} as part of the
290-
* `UrlCreationOptions`.
291-
*@see {@link UrlCreationOptions#preserveFragment}
292-
*@see {@link Router#createUrlTree}
293-
*/
294-
@Input({transform:booleanAttribute})preserveFragment:boolean=false;
295-
296-
/**
297-
* Passed to {@link Router#navigateByUrl} as part of the
298-
* `NavigationBehaviorOptions`.
299-
*@see {@link NavigationBehaviorOptions#skipLocationChange}
300-
*@see {@link Router#navigateByUrl}
301-
*/
302-
@Input({transform:booleanAttribute})skipLocationChange:boolean=false;
303-
304-
/**
305-
* Passed to {@link Router#navigateByUrl} as part of the
306-
* `NavigationBehaviorOptions`.
307-
*@see {@link NavigationBehaviorOptions#replaceUrl}
308-
*@see {@link Router#navigateByUrl}
309-
*/
310-
@Input({transform:booleanAttribute})replaceUrl:boolean=false;
311-
312317
/**
313318
* Modifies the tab index if there was not a tabindex attribute on the element during
314319
* instantiation.
@@ -323,24 +328,7 @@ export class RouterLink implements OnChanges, OnDestroy {
323328
/**@docs-private */
324329
// TODO(atscott): Remove changes parameter in major version as a breaking change.
325330
ngOnChanges(changes?:SimpleChanges):void{
326-
if(
327-
ngDevMode&&
328-
isUrlTree(this.routerLinkInput)&&
329-
(this.fragment!==undefined||
330-
this.queryParams||
331-
this.queryParamsHandling||
332-
this.preserveFragment||
333-
this.relativeTo)
334-
){
335-
thrownewRuntimeError(
336-
RuntimeErrorCode.INVALID_ROUTER_LINK_INPUTS,
337-
'Cannot configure queryParams or fragment when using a UrlTree as the routerLink input value.',
338-
);
339-
}
340-
if(this.isAnchorElement){
341-
this.updateHref();
342-
this.subscribeToNavigationEventsIfNecessary();
343-
}
331+
this.changes.set({});
344332
// This is subscribed to by `RouterLinkActive` so that it knows to update when there are changes
345333
// to the RouterLinks it's tracking.
346334
this.onChanges.next(this);
@@ -427,15 +415,6 @@ export class RouterLink implements OnChanges, OnDestroy {
427415
this.subscription?.unsubscribe();
428416
}
429417

430-
privateupdateHref():void{
431-
consturlTree=this.urlTree;
432-
this.reactiveHref.set(
433-
urlTree!==null&&this.locationStrategy
434-
?(this.locationStrategy?.prepareExternalUrl(this.router.serializeUrl(urlTree))??'')
435-
:null,
436-
);
437-
}
438-
439418
privateapplyAttributeValue(attrName:string,attrValue:string|null){
440419
constrenderer=this.renderer;
441420
constnativeElement=this.el.nativeElement;
@@ -446,21 +425,32 @@ export class RouterLink implements OnChanges, OnDestroy {
446425
}
447426
}
448427

428+
/**@internal */
429+
_urlTree=linkedSignal({
430+
source:()=>{
431+
this.changes();// Recompute source signal whenever inputs change.
432+
433+
constrouterLinkInput=this.routerLinkInput;
434+
if(routerLinkInput===null){
435+
returnsignal(null);
436+
}elseif(isUrlTree(routerLinkInput)){
437+
returnsignal(routerLinkInput);
438+
}
439+
returnthis.router.createComputedUrlTree(routerLinkInput,{
440+
// If the `relativeTo` input is not defined, we want to use `this.route` by default.
441+
// Otherwise, we should use the value provided by the user in the input.
442+
relativeTo:this.relativeTo!==undefined ?this.relativeTo :this.route,
443+
queryParams:this.queryParams,
444+
fragment:this.fragment,
445+
queryParamsHandling:this.queryParamsHandling,
446+
preserveFragment:this.preserveFragment,
447+
});
448+
},
449+
computation:(v)=>v(),
450+
});
451+
449452
geturlTree():UrlTree|null{
450-
if(this.routerLinkInput===null){
451-
returnnull;
452-
}elseif(isUrlTree(this.routerLinkInput)){
453-
returnthis.routerLinkInput;
454-
}
455-
returnthis.router.createUrlTree(this.routerLinkInput,{
456-
// If the `relativeTo` input is not defined, we want to use `this.route` by default.
457-
// Otherwise, we should use the value provided by the user in the input.
458-
relativeTo:this.relativeTo!==undefined ?this.relativeTo :this.route,
459-
queryParams:this.queryParams,
460-
fragment:this.fragment,
461-
queryParamsHandling:this.queryParamsHandling,
462-
preserveFragment:this.preserveFragment,
463-
});
453+
returnuntracked(this._urlTree);
464454
}
465455
}
466456

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp