-
Notifications
You must be signed in to change notification settings - Fork 25.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(router): routerLinkActive should not throw when not initialized #13273
Conversation
2c171ff
to
a925091
Compare
25715c6
to
6966594
Compare
948d87d
to
8a4561b
Compare
@@ -1959,6 +1959,7 @@ describe('Integration', () => { | |||
@Component({ | |||
template: `<a routerLink="/team" routerLinkActive #rla="routerLinkActive"></a> | |||
<p>{{rla.isActive}}</p> | |||
<span *ngIf="rla.isActive"></span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing a .not.toThrow()
somewhere ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do u think it makes sense to assert that component creation doesn't throw an error?
expect(() => f = TestBed.createComponent(ComponentWithRouterLink)).not.toThrow();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do u think it makes sense to assert that component creation doesn't throw an error?
If it used to throw yes, otherwise no
@@ -89,46 +89,50 @@ export class RouterLinkActive implements OnChanges, | |||
|
|||
private classes: string[] = []; | |||
private subscription: Subscription; | |||
private _isActive: boolean = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isActive for consistency
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isActive
without underscore is a public prop https://github.com/angular/angular/blob/master/modules/%40angular/router/src/directives/router_link_active.ts#L103
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make all other private prop start with _ then please
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can rename it to something without underscore.
state
, active
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whatever sounds best for you and you feel describes it best
|
||
ngAfterContentInit(): void { | ||
this.links.changes.subscribe(s => this.update()); | ||
this.linksWithHrefs.changes.subscribe(s => this.update()); | ||
this.links.changes.subscribe(() => this.update()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_ =>
Please split the changes into 2 commits:
Also quickly describe what this PR fixes, add a unit test. Thanks |
Please re-arrange in 1 refactor + 1 fix before it can be reviewed & merged |
9942261
to
1ef95ce
Compare
} else { | ||
this.classes = data.split(' '); | ||
} | ||
this.classes = (Array.isArray(data) ? data : data.split(' ')).filter(c => !!c); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const classes = Array.isArray(data) ? data : data.split(' ');
this classes = classes.filter(c=> c);
@@ -6,7 +6,7 @@ | |||
* found in the LICENSE file at https://angular.io/license | |||
*/ | |||
|
|||
import {AfterContentInit, ContentChildren, Directive, ElementRef, Input, OnChanges, OnDestroy, QueryList, Renderer} from '@angular/core'; | |||
import {AfterContentInit, ChangeDetectorRef, ContentChildren, Directive, ElementRef, Input, OnChanges, OnDestroy, QueryList, Renderer} from '@angular/core'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move to 2nd commit (.d.ts as well)
@@ -118,13 +121,15 @@ export class RouterLinkActive implements OnChanges, | |||
|
|||
private update(): void { | |||
if (!this.links || !this.linksWithHrefs || !this.router.navigated) return; | |||
|
|||
const isActive = this.hasActiveLink(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const hasActiveLinks()
? (also add "s" on the method name)
this.active = isActive; | ||
this.classes.forEach( | ||
c => this.renderer.setElementClass(this.element.nativeElement, c, isActive)); | ||
this.cdr.detectChanges(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do you actually detectChanges here ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otherwise it throws Expression ___ has changed after it was checked
. We change get isActive()
inside ngOnChanges
which is forbidden without the second cycle of change detection. And I tried almost everything to avoid it but without any success.
One of the reasons why a separate directive was a bad idea.
cbb8969
to
0fb7db8
Compare
8c6a616
to
519eea3
Compare
519eea3
to
fb5bd34
Compare
@vicb ready for review |
@vicb can you re-review? This fix is important for material. |
|
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Fixes #13270
if we have a template with only interpolation it works fine:
but if we have bindings it fails:
Getter is called before ContentChildren is initialized thus it failed here with the error
Cannot read property some of undefined