Skip to content

Commit 73467a8

Browse files
committed
fix(sidebar-nav): add missing dropdownMode
- `path`: close inactive sidebar-nav-group on active route change only - `close`: close open sidebar-nav-group on other group click - `none`: keep sidebar-nav-group open
1 parent ac0adc8 commit 73467a8

File tree

6 files changed

+113
-52
lines changed

6 files changed

+113
-52
lines changed

projects/coreui-angular/src/lib/sidebar/sidebar-nav/sidebar-nav-group.component.html

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1-
<a class="nav-link nav-group-toggle"
2-
href
3-
(click)="toggleGroup($event)"
4-
[cHtmlAttr]="item.attributes">
1+
<a (click)="toggleGroup($event)"
2+
[cHtmlAttr]="item.attributes"
3+
class="nav-link nav-group-toggle"
4+
href>
55
<ng-container *ngTemplateOutlet="iconTemplate ; context: {$implicit: item}"></ng-container>
66
<ng-container>{{ item.name }}</ng-container>
77
<span *ngIf="helper.hasBadge(item)" [ngClass]="item | cSidebarNavBadge">{{ item.badge.text }}</span>
88
</a>
99
<c-sidebar-nav
10+
(@openClose.done)="onAnimationDone($event)"
11+
(@openClose.start)="onAnimationStart($event)"
12+
[@openClose]="open ? 'open' : 'closed'"
13+
[dropdownMode]="dropdownMode"
1014
[groupItems]="true"
1115
[navItems]="navItems"
12-
[@openClose]="open ? 'open' : 'closed'"
13-
(@openClose.start)="onAnimationStart($event)"
14-
(@openClose.done)="onAnimationDone($event)"
1516
[ngStyle]="display"
1617
>
1718
</c-sidebar-nav>
@@ -21,8 +22,8 @@
2122
<ng-template [ngIf]="item?.iconComponent">
2223
<svg
2324
[cIcon]="item.iconComponent?.content"
24-
[name]="item.iconComponent?.name"
2525
[customClasses]="item | cSidebarNavIcon"
26+
[name]="item.iconComponent?.name"
2627
></svg>
2728
</ng-template>
2829
<span *ngIf="!item?.icon && !item?.iconComponent" [ngClass]="item | cSidebarNavIcon"></span>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { TestBed } from '@angular/core/testing';
2+
3+
import { SidebarNavGroupService } from './sidebar-nav-group.service';
4+
5+
describe('SidebarNavGroupService', () => {
6+
let service: SidebarNavGroupService;
7+
8+
beforeEach(() => {
9+
TestBed.configureTestingModule({
10+
providers: [SidebarNavGroupService]
11+
});
12+
service = TestBed.inject(SidebarNavGroupService);
13+
});
14+
15+
it('should be created', () => {
16+
expect(service).toBeTruthy();
17+
});
18+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { Injectable } from '@angular/core';
2+
import { BehaviorSubject } from 'rxjs';
3+
4+
import { SidebarNavGroupComponent } from './sidebar-nav.component';
5+
6+
export interface ISidebarAction {
7+
open?: boolean;
8+
sidebarNavGroup?: SidebarNavGroupComponent;
9+
}
10+
11+
@Injectable()
12+
export class SidebarNavGroupService {
13+
14+
constructor() { }
15+
16+
private sidebarNavGroupState = new BehaviorSubject<ISidebarAction>({});
17+
sidebarNavGroupState$ = this.sidebarNavGroupState.asObservable();
18+
19+
toggle(action: ISidebarAction): void {
20+
this.sidebarNavGroupState.next(action);
21+
}
22+
}

projects/coreui-angular/src/lib/sidebar/sidebar-nav/sidebar-nav.component.html

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
<ng-container *ngFor="let item of navItemsArray">
22
<ng-container [ngSwitch]="helper.itemType(item)">
33
<c-sidebar-nav-group
4+
#rla="routerLinkActive"
45
*ngSwitchCase="'group'"
6+
[dropdownMode]="dropdownMode"
57
[item]="item"
68
[ngClass]="item | cSidebarNavItemClass"
7-
routerLinkActive="show"
8-
#rla="routerLinkActive"
99
[routerLinkActiveOptions]="{exact: true}"
10+
routerLinkActive="show"
1011
>
1112
</c-sidebar-nav-group>
1213
<c-sidebar-nav-divider
1314
*ngSwitchCase="'divider'"
15+
[cHtmlAttr]="item.attributes ?? {}"
1416
[item]="item"
15-
[ngClass]="item | cSidebarNavItemClass"
16-
[cHtmlAttr]="item.attributes ?? {}">
17+
[ngClass]="item | cSidebarNavItemClass">
1718
</c-sidebar-nav-divider>
1819
<c-sidebar-nav-title
1920
*ngSwitchCase="'title'"
21+
[cHtmlAttr]="item.attributes ?? {}"
2022
[item]="item"
21-
[ngClass]="item | cSidebarNavItemClass"
22-
[cHtmlAttr]="item.attributes ?? {}">
23+
[ngClass]="item | cSidebarNavItemClass">
2324
</c-sidebar-nav-title>
2425
<c-sidebar-nav-label
2526
*ngSwitchCase="'label'"
@@ -30,10 +31,10 @@
3031
*ngSwitchCase="'empty'">
3132
</ng-container>
3233
<c-sidebar-nav-link
34+
(linkClick)="hideMobile()"
3335
*ngSwitchDefault
3436
[item]="item"
3537
[ngClass]="item | cSidebarNavItemClass"
36-
(linkClick)="hideMobile()"
3738
>
3839
</c-sidebar-nav-link>
3940
</ng-container>

projects/coreui-angular/src/lib/sidebar/sidebar-nav/sidebar-nav.component.ts

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
OnInit,
99
Optional,
1010
Renderer2,
11-
SimpleChanges
11+
SimpleChanges,
12+
ViewChild
1213
} from '@angular/core';
1314
import { NavigationEnd, Router } from '@angular/router';
1415

@@ -19,15 +20,26 @@ import { SidebarComponent } from '../sidebar/sidebar.component';
1920
import { Observable, Subscription } from 'rxjs';
2021
import { filter } from 'rxjs/operators';
2122
import { animate, AnimationEvent, state, style, transition, trigger } from '@angular/animations';
23+
import { SidebarNavGroupService } from './sidebar-nav-group.service';
2224

2325
@Component({
2426
selector: 'c-sidebar-nav',
2527
templateUrl: './sidebar-nav.component.html',
2628
styleUrls: ['./sidebar-nav.component.scss']
2729
})
2830
export class SidebarNavComponent implements OnChanges {
31+
32+
constructor(
33+
@Optional() public sidebar: SidebarComponent,
34+
public helper: SidebarNavHelper,
35+
public router: Router,
36+
private renderer: Renderer2,
37+
private hostElement: ElementRef,
38+
private sidebarService: SidebarService
39+
) { }
40+
2941
@Input() navItems?: INavData[] = [];
30-
@Input() dropdownMode?: 'closeInactive' | 'noAction' | 'openActive' = 'closeInactive';
42+
@Input() dropdownMode: 'path' | 'none' | 'close' = 'path';
3143
@Input() groupItems?: boolean;
3244
@Input() compact?: boolean;
3345

@@ -48,15 +60,6 @@ export class SidebarNavComponent implements OnChanges {
4860

4961
public navItemsArray: INavData[] = [];
5062

51-
constructor(
52-
@Optional() public sidebar: SidebarComponent,
53-
public helper: SidebarNavHelper,
54-
public router: Router,
55-
private renderer: Renderer2,
56-
private hostElement: ElementRef,
57-
private sidebarService: SidebarService
58-
) { }
59-
6063
public ngOnChanges(changes: SimpleChanges): void {
6164
this.navItemsArray = Array.isArray(this.navItems) ? this.navItems.slice() : [];
6265
}
@@ -89,53 +92,61 @@ export class SidebarNavComponent implements OnChanges {
8992
]
9093
})
9194
export class SidebarNavGroupComponent implements OnInit, OnDestroy {
95+
96+
constructor(
97+
private router: Router,
98+
private renderer: Renderer2,
99+
private hostElement: ElementRef,
100+
public helper: SidebarNavHelper,
101+
private sidebarNavGroupService: SidebarNavGroupService
102+
) {
103+
this.navigationEndObservable = router.events.pipe(
104+
filter((event: any) => event instanceof NavigationEnd)
105+
) as Observable<NavigationEnd>;
106+
}
107+
92108
@Input() item: any;
93-
@Input() dropdownMode: 'closeInactive' | 'noAction' | 'openActive' = 'closeInactive';
94-
// @ts-ignore
95-
@Input() show: boolean;
109+
@Input() dropdownMode: 'path' | 'none' | 'close' = 'path';
110+
@Input() show?: boolean;
96111

97112
@HostBinding('class')
98-
// tslint:disable-next-line:typedef
99113
get hostClasses(): any {
100114
return {
101115
'nav-group': true,
102116
show: this.open
103117
};
104118
}
105119

106-
// todo: dropdownMode
120+
@ViewChild(SidebarNavComponent, { read: ElementRef }) sidebarNav!: ElementRef;
107121

108122
navigationEndObservable: Observable<NavigationEnd>;
109-
// @ts-ignore
110-
navSubscription: Subscription;
123+
navSubscription!: Subscription;
124+
navGroupSubscription!: Subscription;
111125

112-
// @ts-ignore
113-
public open: boolean;
126+
public open!: boolean;
114127
public navItems: INavData[] = [];
115128
public display: any = { display: 'block' };
116129

117-
constructor(
118-
private router: Router,
119-
public helper: SidebarNavHelper,
120-
private hostElement: ElementRef
121-
) {
122-
this.navigationEndObservable = router.events.pipe(
123-
filter((event: any) => event instanceof NavigationEnd)
124-
) as Observable<NavigationEnd>;
125-
}
126-
127130
ngOnInit(): void {
128131

129132
this.navItems = [...this.item.children];
130133

131134
this.navSubscription = this.navigationEndObservable.subscribe((event: NavigationEnd) => {
132-
const samePath = this.samePath(event.url);
133-
this.openGroup(samePath);
135+
if (this.dropdownMode !== 'none') {
136+
const samePath = this.samePath(event.url);
137+
this.openGroup(samePath);
138+
}
134139
});
135140

136141
if (this.samePath(this.router.routerState.snapshot.url)) {
137142
this.openGroup(true);
138143
}
144+
145+
this.navGroupSubscription = this.sidebarNavGroupService.sidebarNavGroupState$.subscribe(next => {
146+
if (this.dropdownMode === 'close' && next.sidebarNavGroup && next.sidebarNavGroup !== this) {
147+
this.openGroup(false);
148+
}
149+
});
139150
}
140151

141152
samePath(url: string): boolean {
@@ -154,17 +165,22 @@ export class SidebarNavGroupComponent implements OnInit, OnDestroy {
154165

155166
toggleGroup($event: any): void {
156167
$event.preventDefault();
157-
this.open = !this.open;
168+
this.openGroup(!this.open);
169+
if (this.open) {
170+
this.sidebarNavGroupService.toggle({ open: this.open, sidebarNavGroup: this });
171+
}
158172
}
159173

160174
ngOnDestroy(): void {
161175
this.navSubscription.unsubscribe();
162176
}
163177

164178
onAnimationStart($event: AnimationEvent) {
165-
setTimeout(() => {
166-
this.display = { display: 'block' };
167-
});
179+
this.display = { display: 'block' };
180+
if ($event.toState === 'open') {
181+
const host = this.sidebarNav.nativeElement;
182+
this.renderer.setStyle(host, 'height', `${host['scrollHeight']}px`);
183+
}
168184
}
169185

170186
onAnimationDone($event: AnimationEvent) {

projects/coreui-angular/src/lib/sidebar/sidebar.module.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { SidebarToggleDirective } from './sidebar-toggle/sidebar-toggle.directiv
1111
import { SidebarTogglerComponent } from './sidebar-toggler/sidebar-toggler.component';
1212
import { SidebarHeaderComponent } from './sidebar-header/sidebar-header.component';
1313
import { SidebarFooterComponent } from './sidebar-footer/sidebar-footer.component';
14+
import { SidebarNavGroupService } from './sidebar-nav/sidebar-nav-group.service';
1415

1516
import { SharedModule } from '../shared';
1617

@@ -30,6 +31,7 @@ import {
3031
} from './sidebar-nav';
3132

3233

34+
3335
@NgModule({
3436
declarations: [
3537
SidebarComponent,
@@ -68,7 +70,8 @@ import {
6870
],
6971
providers: [
7072
SidebarService,
71-
SidebarNavHelper
73+
SidebarNavHelper,
74+
SidebarNavGroupService
7275
],
7376
})
7477
export class SidebarModule { }

0 commit comments

Comments
 (0)