fix(router): ensure routerLinkActive updates when associated routerLinks change (#38511)
This commit introduces a new subscription in the `routerLinkActive` directive which triggers an update when any of its associated routerLinks have changes. `RouterLinkActive` not only needs to know when links are added or removed, but it also needs to know about if a link it already knows about changes in some way. Quick note that `from...mergeAll` is used instead of just a simple `merge` (or `scheduled...mergeAll`) to avoid introducing new rxjs operators in order to keep bundle size down. Fixes #18469 PR Close #38511
This commit is contained in:
@ -4344,7 +4344,7 @@ describe('Integration', () => {
|
||||
})));
|
||||
});
|
||||
|
||||
describe('routerActiveLink', () => {
|
||||
describe('routerLinkActive', () => {
|
||||
it('should set the class when the link is active (a tag)',
|
||||
fakeAsync(inject([Router, Location], (router: Router, location: Location) => {
|
||||
const fixture = createRoot(router, RootCmp);
|
||||
@ -4494,6 +4494,29 @@ describe('Integration', () => {
|
||||
advance(fixture);
|
||||
expect(paragraph.textContent).toEqual('false');
|
||||
}));
|
||||
|
||||
it('should not trigger change detection when active state has not changed', fakeAsync(() => {
|
||||
@Component({
|
||||
template: `<div id="link" routerLinkActive="active" [routerLink]="link"></div>`,
|
||||
})
|
||||
class LinkComponent {
|
||||
link = 'notactive';
|
||||
}
|
||||
|
||||
@Component({template: ''})
|
||||
class SimpleComponent {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [RouterTestingModule.withRoutes([{path: '', component: SimpleComponent}])],
|
||||
declarations: [LinkComponent, SimpleComponent]
|
||||
});
|
||||
|
||||
const fixture = createRoot(TestBed.inject(Router), LinkComponent);
|
||||
fixture.componentInstance.link = 'stillnotactive';
|
||||
fixture.detectChanges(false /** checkNoChanges */);
|
||||
expect(TestBed.inject(NgZone).hasPendingMicrotasks).toBe(false);
|
||||
}));
|
||||
});
|
||||
|
||||
describe('lazy loading', () => {
|
||||
|
@ -14,6 +14,54 @@ import {RouterTestingModule} from '@angular/router/testing';
|
||||
|
||||
describe('Integration', () => {
|
||||
describe('routerLinkActive', () => {
|
||||
it('should update when the associated routerLinks change - #18469', fakeAsync(() => {
|
||||
@Component({
|
||||
template: `
|
||||
<a id="first-link" [routerLink]="[firstLink]" routerLinkActive="active">{{firstLink}}</a>
|
||||
<div id="second-link" routerLinkActive="active">
|
||||
<a [routerLink]="[secondLink]">{{secondLink}}</a>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
class LinkComponent {
|
||||
firstLink = 'link-a';
|
||||
secondLink = 'link-b';
|
||||
|
||||
changeLinks(): void {
|
||||
const temp = this.secondLink;
|
||||
this.secondLink = this.firstLink;
|
||||
this.firstLink = temp;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({template: 'simple'})
|
||||
class SimpleCmp {
|
||||
}
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [RouterTestingModule.withRoutes(
|
||||
[{path: 'link-a', component: SimpleCmp}, {path: 'link-b', component: SimpleCmp}])],
|
||||
declarations: [LinkComponent, SimpleCmp]
|
||||
});
|
||||
|
||||
const router: Router = TestBed.inject(Router);
|
||||
const fixture = createRoot(router, LinkComponent);
|
||||
const firstLink = fixture.debugElement.query(p => p.nativeElement.id === 'first-link');
|
||||
const secondLink = fixture.debugElement.query(p => p.nativeElement.id === 'second-link');
|
||||
router.navigateByUrl('/link-a');
|
||||
advance(fixture);
|
||||
|
||||
expect(firstLink.nativeElement.classList).toContain('active');
|
||||
expect(secondLink.nativeElement.classList).not.toContain('active');
|
||||
|
||||
fixture.componentInstance.changeLinks();
|
||||
fixture.detectChanges();
|
||||
advance(fixture);
|
||||
|
||||
expect(firstLink.nativeElement.classList).not.toContain('active');
|
||||
expect(secondLink.nativeElement.classList).toContain('active');
|
||||
}));
|
||||
|
||||
it('should not cause infinite loops in the change detection - #15825', fakeAsync(() => {
|
||||
@Component({selector: 'simple', template: 'simple'})
|
||||
class SimpleCmp {
|
||||
|
Reference in New Issue
Block a user