Skip to content

Commit 8d35dc1

Browse files
fix(uiSrefActive): Fix nested UISrefActive where UISref components are added/removed dynamically (#811)
Fixes #760
1 parent 36632f2 commit 8d35dc1

File tree

2 files changed

+68
-7
lines changed

2 files changed

+68
-7
lines changed

src/directives/uiSrefStatus.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,9 @@ export class UISrefStatus {
227227

228228
// Watch the @ContentChildren UISref[] components and get their target states
229229
this._srefs$ = new BehaviorSubject(withHostSref(this._srefs.toArray()));
230-
this._srefChangesSub = this._srefs.changes.subscribe((srefs) => this._srefs$.next(withHostSref(srefs)));
230+
this._srefChangesSub = this._srefs.changes.subscribe((srefs: QueryList<UISref>) =>
231+
this._srefs$.next(withHostSref(srefs.toArray()))
232+
);
231233

232234
const targetStates$: Observable<TargetState[]> = this._srefs$.pipe(
233235
switchMap((srefs: UISref[]) => combineLatest<TargetState[]>(srefs.map((sref) => sref.targetState$)))

test/uiSrefActive/uiSrefActive.spec.ts

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
import { Component } from '@angular/core';
1+
import { Component, Type } from '@angular/core';
22
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
33
import { By } from '@angular/platform-browser';
44

55
import { UIRouter } from '@uirouter/core';
6-
import { UIRouterModule } from '../../src/uiRouterNgModule';
76
import { UISrefActive } from '../../src';
7+
import { UIRouterModule } from '../../src/uiRouterNgModule';
88

99
describe('uiSrefActive', () => {
10-
const tick = () => new Promise(resolve => setTimeout(resolve));
10+
const tick = () => new Promise((resolve) => setTimeout(resolve));
1111

12-
const initialize = (Component, states) => {
12+
const initialize = <T>(ComponentClass: Type<T>, states) => {
1313
const fixture = TestBed.configureTestingModule({
14-
declarations: [Component],
14+
declarations: [ComponentClass],
1515
imports: [UIRouterModule.forRoot({ useHash: true, states })],
16-
}).createComponent(Component);
16+
}).createComponent(ComponentClass);
1717
fixture.detectChanges();
1818

1919
return fixture;
@@ -65,4 +65,63 @@ describe('uiSrefActive', () => {
6565
});
6666
}));
6767
});
68+
69+
describe('on a parent element', () => {
70+
it('applies the active class when any child link is active', async(async () => {
71+
const template = `
72+
<li uiSrefActive="active">
73+
<a uiSref="statea">State A</a>
74+
<a uiSref="statec">State C</a>
75+
</li>
76+
`;
77+
@Component({ template })
78+
class TestComponent {}
79+
80+
const fixture = initialize(TestComponent, [{ name: 'statea' }, { name: 'stateb' }, { name: 'statec' }]);
81+
82+
const des = fixture.debugElement.queryAll(By.directive(UISrefActive));
83+
const router = fixture.debugElement.injector.get(UIRouter);
84+
85+
await router.stateService.go('statea').then(tick);
86+
expect(des[0].nativeElement.classList).toContain('active');
87+
88+
await router.stateService.go('stateb').then(tick);
89+
expect(des[0].nativeElement.classList).not.toContain('active');
90+
91+
await router.stateService.go('statec').then(tick);
92+
expect(des[0].nativeElement.classList).toContain('active');
93+
}));
94+
95+
// Test for https://github.com/ui-router/angular/issues/760
96+
it('can dynamically add or remove nested uiSref', async(async () => {
97+
const template = `
98+
<li id="parent" uiSrefActive="active">
99+
<a uiSref="statea"></a>
100+
<a uiSref="stateb" *ngIf="show"></a>
101+
</li>
102+
`;
103+
@Component({ template })
104+
class TestComponent {
105+
public show = false;
106+
}
107+
108+
const states = [{ name: 'statea' }, { name: 'stateb' }, { name: 'statec' }];
109+
const fixture = initialize(TestComponent, states);
110+
111+
const des = fixture.debugElement.queryAll(By.directive(UISrefActive));
112+
const router = fixture.debugElement.injector.get(UIRouter);
113+
114+
await router.stateService.go('statea').then(tick);
115+
expect(des[0].nativeElement.classList).toContain('active');
116+
117+
fixture.componentInstance.show = true;
118+
fixture.detectChanges();
119+
120+
await router.stateService.go('stateb').then(tick);
121+
expect(des[0].nativeElement.classList).toContain('active');
122+
123+
await router.stateService.go('statec').then(tick);
124+
expect(des[0].nativeElement.classList).not.toContain('active');
125+
}));
126+
});
68127
});

0 commit comments

Comments
 (0)