Skip to content

Commit 786073f

Browse files
authored
Merge pull request #3063 from IgniteUI/nav-drawer-hierarchical
feat(nav drawer): hierachical navigation sample with igx-tree
2 parents 9a3156c + a229839 commit 786073f

11 files changed

Lines changed: 284 additions & 32 deletions

live-editing/configs/NavDrawerConfigGenerator.ts

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ IgxIconModule,
44
IgxLayoutModule,
55
IgxNavigationDrawerModule,
66
IgxRippleModule,
7-
IgxToggleModule} from 'igniteui-angular';
7+
IgxToggleModule,
8+
IgxTreeModule} from 'igniteui-angular';
89
import {AppModuleConfig, Config, IConfigGenerator} from 'igniteui-live-editing'
910
export class NavdrawerConfigGenerator implements IConfigGenerator {
1011

@@ -124,6 +125,55 @@ export class NavdrawerConfigGenerator implements IConfigGenerator {
124125
shortenComponentPathBy: "/menus/navdrawer/"
125126
}));
126127

128+
configs.push(new Config({
129+
component: 'NavDrawerHierarchicalComponent',
130+
appModuleConfig: new AppModuleConfig({
131+
imports: [
132+
'IgxButtonModule',
133+
'IgxIconModule',
134+
'IgxLayoutModule',
135+
'IgxNavigationDrawerModule',
136+
'IgxRippleModule',
137+
'IgxToggleModule',
138+
'NavDrawerHierarchicalComponent',
139+
'IgxTreeModule',
140+
'RouterModule'
141+
],
142+
ngDeclarations: ['NavDrawerHierarchicalComponent'],
143+
ngImports: [
144+
'IgxButtonModule',
145+
'IgxIconModule',
146+
'IgxLayoutModule',
147+
'IgxNavigationDrawerModule',
148+
'IgxRippleModule',
149+
'IgxToggleModule',
150+
'IgxTreeModule',
151+
`
152+
RouterModule.forRoot([
153+
{ path: 'grid', component: NavDrawerHierarchicalComponent, data: { displayName: 'Grid' } },
154+
{ path: 'tree-grid', component: NavDrawerHierarchicalComponent, data: { displayName: 'Tree Grid' } },
155+
{ path: 'hierarchical-grid', component: NavDrawerHierarchicalComponent, data: { displayName: 'Hierarchical Grid' } },
156+
{ path: 'pivot-grid', component: NavDrawerHierarchicalComponent, data: { displayName: 'Pivot Grid' } },
157+
{ path: 'area-chart', component: NavDrawerHierarchicalComponent, data: { displayName: 'Area Chart' } },
158+
{ path: 'bar-chart', component: NavDrawerHierarchicalComponent, data: { displayName: 'Bar Chart' } },
159+
{ path: 'column-chart', component: NavDrawerHierarchicalComponent, data: { displayName: 'Column Chart' } },
160+
{ path: 'pie-chart', component: NavDrawerHierarchicalComponent, data: { displayName: 'Pie Chart' } },
161+
{ path: 'action-strip', component: NavDrawerHierarchicalComponent, data: { displayName: 'Action Strip' } },
162+
{ path: 'dialog', component: NavDrawerHierarchicalComponent, data: { displayName: 'Dialog' } },
163+
{ path: 'drag-drop', component: NavDrawerHierarchicalComponent, data: { displayName: 'Drag and Drop' } },
164+
{ path: 'dock-manager', component: NavDrawerHierarchicalComponent, data: { displayName: 'Dock Manager' } },
165+
{ path: 'expansion-panel', component: NavDrawerHierarchicalComponent, data: { displayName: 'Exspansion Panel' } },
166+
{ path: 'layout', component: NavDrawerHierarchicalComponent, data: { displayName: 'Layout Manager' } },
167+
{ path: 'banner', component: NavDrawerHierarchicalComponent, data: { displayName: 'Banner' } },
168+
{ path: 'snackbar', component: NavDrawerHierarchicalComponent, data: { displayName: 'Snackbar' } },
169+
{ path: 'toast', component: NavDrawerHierarchicalComponent, data: { displayName: 'Toast' } }
170+
])
171+
`
172+
]
173+
}),
174+
shortenComponentPathBy: "/menus/navdrawer/"
175+
}));
176+
127177
return configs;
128178
}
129179
}

src/app/app.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { BrowserModule, HammerModule } from '@angular/platform-browser';
55
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
66
import {
77
IgxAutocompleteModule, IgxButtonModule, IgxDropDownModule,
8-
IgxIconModule, IgxInputGroupModule, IgxLayoutModule, IgxNavbarModule, IgxNavigationDrawerModule, IgxRippleModule
8+
IgxIconModule, IgxInputGroupModule, IgxLayoutModule, IgxNavbarModule, IgxNavigationDrawerModule, IgxRippleModule, IgxTreeModule
99
} from 'igniteui-angular';
1010
import { AppRoutingModule } from './app-routing.module';
1111
import { AppComponent } from './app.component';
@@ -31,6 +31,7 @@ import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
3131
IgxIconModule,
3232
IgxLayoutModule,
3333
IgxInputGroupModule,
34+
IgxTreeModule,
3435
BrowserModule,
3536
BrowserAnimationsModule,
3637
IgxButtonModule,

src/app/index/index.component.html

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,45 @@
88
</div>
99

1010
<!-- Home -->
11-
<span igxDrawerItem igxRipple routerLink="{{homeRouteItem.path}}" routerLinkActive="igx-nav-drawer__item--active navdrawer-ellipsis">
11+
<span igxDrawerItem igxRipple [routerLink]="homeRouteItem.path" routerLinkActive="igx-nav-drawer__item--active">
1212
<igx-icon family="material">home</igx-icon>
13-
{{homeRouteItem.displayName}}
13+
<span>{{homeRouteItem.displayName}}</span>
1414
</span>
1515

1616
<!-- Search -->
1717
<igx-input-group type="search" class="searchGroup">
1818
<igx-prefix>
1919
<igx-icon>search</igx-icon>
2020
</igx-prefix>
21-
<input #search igxInput placeholder="Search samples" [(ngModel)]="searchValue" (ngModelChange)="searchValueChanged()">
21+
<input #search igxInput placeholder="Search samples" (focus)="createSearchSub(search)" [(ngModel)]="searchValue">
2222
<igx-suffix *ngIf="search.value.length > 0" (click)="clearSearchValue()">
2323
<igx-icon>clear</igx-icon>
2424
</igx-suffix>
2525
</igx-input-group>
2626

27-
<span *ngFor="let navItem of currentNavItems">
28-
<!-- Header -->
27+
<igx-tree #tree>
28+
<igx-tree-node [data]="item.name" *ngFor="let item of currentNavItems">
29+
{{ item.name }}
30+
<igx-tree-node [data]="route.displayName" *ngFor="let route of item.children">
31+
<a igxTreeNodeLink [routerLink]="route.path">{{ route.displayName }}</a>
32+
</igx-tree-node>
33+
</igx-tree-node>
34+
</igx-tree>
35+
36+
<!-- <span *ngFor="let navItem of currentNavItems">
37+
2938
<span igxDrawerItem igxRipple routerLinkActive="igx-nav-drawer__item--active navdrawer-ellipsis" (click)="toggleParent('header' + navItem.name)">
3039
<igx-icon family="material">{{convertNodeStateToIcon('header' + navItem.name)}}</igx-icon>
3140
<span class="navdrawer-ellipsis" style="vertical-align: middle">{{navItem.name}}</span>
3241
</span>
33-
<!-- Children -->
42+
3443
<span [id]="'header' + navItem.name" style="display:none">
3544
<span [id]="'child' + routeItem.displayName" class="innerItem navdrawer-ellipsis" *ngFor="let routeItem of navItem.children" igxDrawerItem igxRipple
36-
routerLink="{{routeItem.path}}" routerLinkActive="igx-nav-drawer__item--active">
45+
[routerLink]="routeItem.path" routerLinkActive="igx-nav-drawer__item--active">
3746
{{routeItem.displayName}}
3847
</span>
3948
</span>
40-
</span>
49+
</span> -->
4150
</nav>
4251
</ng-template>
4352
</igx-nav-drawer>

src/app/index/index.component.ts

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { AfterViewInit, ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
22
import { NavigationStart, Route, Router } from '@angular/router';
3-
import { IgxNavigationDrawerComponent } from 'igniteui-angular';
4-
import { filter } from 'rxjs/operators';
3+
import { IgxNavigationDrawerComponent, IgxTreeComponent } from 'igniteui-angular';
4+
import { fromEvent, Subscription } from 'rxjs';
5+
import { filter, map, debounceTime } from 'rxjs/operators';
56
import { dataDisplayRoutesData } from '../data-display/data-display-routes-data';
67
import { dataEntriesRoutesData } from '../data-entries/data-entries-routes-data';
78
import { gridsRoutesData } from '../grid/grid-routes-data';
@@ -28,6 +29,9 @@ export class IndexComponent implements OnInit, AfterViewInit {
2829
@ViewChild('navdrawer', { read: IgxNavigationDrawerComponent, static: true })
2930
public navdrawer: IgxNavigationDrawerComponent;
3031

32+
@ViewChild('tree', { read: IgxTreeComponent, static: false })
33+
public tree: IgxTreeComponent;
34+
3135
public homeRouteItem: IRouteItem;
3236

3337
public currentNavItems: INavigationItem[] = [];
@@ -113,6 +117,8 @@ export class IndexComponent implements OnInit, AfterViewInit {
113117

114118
private allNavItems: INavigationItem[] = [];
115119

120+
private searchSub: Subscription;
121+
116122
constructor(private router: Router, private cdr: ChangeDetectorRef) {
117123
this.appRoutes = this.getAllSampleRoutes('/samples',
118124
router.config.filter((c) => c.path === 'samples')[0].children, this.modulesRoutes);
@@ -132,6 +138,11 @@ export class IndexComponent implements OnInit, AfterViewInit {
132138
(route: any) => route.path === event.url)[0];
133139
if (routeItem) {
134140
this.selectedDisplayName = routeItem.displayName;
141+
const children = this.tree.findNodes(this.selectedDisplayName);
142+
this.tree.deselectAll();
143+
if (children?.length) {
144+
children[0].selected = true;
145+
}
135146
}
136147

137148
if (event.url !== '/' && !this.navdrawer.pin) {
@@ -155,19 +166,41 @@ export class IndexComponent implements OnInit, AfterViewInit {
155166
const loadedChildItem = loadedParentItem.children.filter(
156167
(routeItem) => routeItem.displayName === loadedRouteItem.displayName)[0];
157168

158-
this.toggleParent('header' + loadedParentItem.name);
159-
document.getElementById('child' + loadedChildItem.displayName).scrollIntoView();
169+
const parents = this.tree.findNodes(loadedParentItem.name);
170+
if (parents?.length) {
171+
parents[0].expanded = true;
172+
parents[0].nativeElement.scrollIntoView();
173+
}
174+
const children = this.tree.findNodes(loadedChildItem.displayName);
175+
if (children?.length) {
176+
children[0].selected = true;
177+
}
160178
this.cdr.detectChanges();
161179
}
162180
}
163181

164-
public searchValueChanged() {
165-
this.currentNavItems = this.filter(this.allNavItems);
182+
public createSearchSub(searchInput: Element) {
183+
if (!this.searchSub) {
184+
const input = fromEvent(searchInput, 'keyup')
185+
.pipe(map<Event, string>(e => (e.currentTarget as HTMLInputElement).value));
186+
const debouncedInput = input.pipe(debounceTime(150));
187+
this.searchSub = debouncedInput.subscribe(() => {
188+
this.currentNavItems = this.filter(this.allNavItems);
189+
this.cdr.detectChanges();
190+
191+
if (this.searchValue !== '') {
192+
this.tree.expandAll();
193+
} else {
194+
this.tree.collapseAll();
195+
}
196+
});
197+
}
166198
}
167199

168200
public clearSearchValue() {
169201
this.searchValue = '';
170-
this.searchValueChanged();
202+
this.currentNavItems = this.filter(this.allNavItems);
203+
this.tree.collapseAll();
171204
}
172205

173206
// toggle a header element from the navigation

src/app/menus/menus-routes-data.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export const menusRoutesData = {
2+
'navbar': { displayName: 'Navbar Basic', parentName: 'Navbar' },
23
'navbar-sample-1': { displayName: 'Navbar Action Button Icon', parentName: 'Navbar' },
34
'navbar-sample-2': { displayName: 'Navbar Custom Action Icon', parentName: 'Navbar' },
45
'navbar-sample-3': { displayName: 'Navbar Navigation Icon', parentName: 'Navbar' },

src/app/menus/menus-routing.module.ts

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,43 +21,72 @@ import { NavDrawerRoutingComponent } from './navdrawer/nav-drawer-routing/nav-dr
2121
import { NavDrawerSimpleComponent } from './navdrawer/nav-drawer-simple/nav-drawer-simple.component';
2222
import { NavDrawerStylingComponent } from './navdrawer/nav-drawer-styling/nav-drawer-styling.component';
2323
import { NavbarCustomTitleComponent } from './navbar/navbar-custom-title/navbar-custom-title.component';
24+
import { NavDrawerHierarchicalComponent } from './navdrawer/nav-drawer-hierarchical/nav-drawer-hierarchical.component';
2425

2526
export const menusRoutes: Routes = [
27+
{
28+
component: NavDrawerHierarchicalComponent,
29+
path: 'navigation-drawer-hierarchical',
30+
data: { displayName: 'Hierachical Drawer Menu' },
31+
children: [
32+
{ path: 'grid', component: NavDrawerHierarchicalComponent, data: { displayName: 'Grid' } },
33+
{ path: 'tree-grid', component: NavDrawerHierarchicalComponent, data: { displayName: 'Tree Grid' } },
34+
{ path: 'hierarchical-grid', component: NavDrawerHierarchicalComponent, data: { displayName: 'Hierarchical Grid' } },
35+
{ path: 'pivot-grid', component: NavDrawerHierarchicalComponent, data: { displayName: 'Pivot Grid' } },
36+
{ path: 'area-chart', component: NavDrawerHierarchicalComponent, data: { displayName: 'Area Chart' } },
37+
{ path: 'bar-chart', component: NavDrawerHierarchicalComponent, data: { displayName: 'Bar Chart' } },
38+
{ path: 'column-chart', component: NavDrawerHierarchicalComponent, data: { displayName: 'Column Chart' } },
39+
{ path: 'pie-chart', component: NavDrawerHierarchicalComponent, data: { displayName: 'Pie Chart' } },
40+
{ path: 'action-strip', component: NavDrawerHierarchicalComponent, data: { displayName: 'Action Strip' } },
41+
{ path: 'dialog', component: NavDrawerHierarchicalComponent, data: { displayName: 'Dialog' } },
42+
{ path: 'drag-drop', component: NavDrawerHierarchicalComponent, data: { displayName: 'Drag and Drop' } },
43+
{ path: 'dock-manager', component: NavDrawerHierarchicalComponent, data: { displayName: 'Dock Manager' } },
44+
{ path: 'expansion-panel', component: NavDrawerHierarchicalComponent, data: { displayName: 'Exspansion Panel' } },
45+
{ path: 'layout', component: NavDrawerHierarchicalComponent, data: { displayName: 'Layout Manager' } },
46+
{ path: 'banner', component: NavDrawerHierarchicalComponent, data: { displayName: 'Banner' } },
47+
{ path: 'snackbar', component: NavDrawerHierarchicalComponent, data: { displayName: 'Snackbar' } },
48+
{ path: 'toast', component: NavDrawerHierarchicalComponent, data: { displayName: 'Toast' } }
49+
]
50+
},
2651
{
2752
component: NavDrawerSimpleComponent,
28-
path: 'navigation-drawer-simple'
53+
path: 'navigation-drawer-simple',
54+
data: { displayName: 'Simple Nav Drawer' }
2955
},
3056
{
3157
component: NavDrawerRoutingComponent,
3258
path: 'navigation-drawer-routing',
59+
data: { displayName: 'Nav Drawer Routing' },
3360
children: [
34-
{ path: '', redirectTo: 'avatar' },
35-
{ path: 'avatar', component: null},
36-
{ path: 'badge', component: null},
37-
{ path: 'button-group', component: null}
61+
{ path: '', redirectTo: 'avatar', pathMatch: 'full', data: { displayName: 'Redirect to Avatar' } },
62+
{ path: 'avatar', component: NavDrawerRoutingComponent, data: { displayName: 'Avatar' } },
63+
{ path: 'badge', component: NavDrawerRoutingComponent, data: { displayName: 'Badge' } },
64+
{ path: 'button-group', component: NavDrawerRoutingComponent, data: { displayName: 'Button Group' } }
3865
]
3966
},
4067
{
4168
component: NavDrawerPinComponent,
42-
path: 'navigation-drawer-pin'
69+
path: 'navigation-drawer-pin',
70+
data: { displayName: 'Pinned Nav Drawer' }
4371
},
4472
{
4573
component: NavDrawerStylingComponent,
4674
path: 'navigation-drawer-styling',
75+
data: { displayName: 'Nav Drawer Styling' },
4776
children: [
48-
{ path: '', redirectTo: 'avatar' },
49-
{ path: 'avatar', component: null },
50-
{ path: 'badge', component: null },
51-
{ path: 'button-group', component: null }
77+
{ path: '', redirectTo: 'avatar', pathMatch: 'full', data: { displayName: 'Redirect to Avatar' } },
78+
{ path: 'avatar', component: NavDrawerStylingComponent, data: { displayName: 'Avatar' } },
79+
{ path: 'badge', component: NavDrawerStylingComponent, data: { displayName: 'Badge' } },
80+
{ path: 'button-group', component: NavDrawerStylingComponent, data: { displayName: 'Button Group' } }
5281
]
5382
},
5483
{
5584
component: NavDrawerMiniComponent,
56-
path: 'navigation-drawer-mini'
85+
path: 'navigation-drawer-mini',
86+
data: { displayName: 'Mini Nav Drawer' }
5787
},
5888
{
5989
component: NavbarComponent,
60-
// tslint:disable-next-line:no-string-literal
6190
data: menusRoutesData['navbar'],
6291
path: 'navbar'
6392
},

src/app/menus/menus.module.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import {
1212
IgxRadioModule,
1313
IgxRippleModule,
1414
IgxSwitchModule,
15-
IgxToggleModule
15+
IgxToggleModule,
16+
IgxTreeModule
1617
} from 'igniteui-angular';
1718
import {
1819
ActionStripParagraphMenuComponent
@@ -35,6 +36,7 @@ import { NavDrawerRoutingComponent } from './navdrawer/nav-drawer-routing/nav-dr
3536
import { NavDrawerSimpleComponent } from './navdrawer/nav-drawer-simple/nav-drawer-simple.component';
3637
import { NavDrawerStylingComponent } from './navdrawer/nav-drawer-styling/nav-drawer-styling.component';
3738
import { NavbarCustomTitleComponent } from './navbar/navbar-custom-title/navbar-custom-title.component';
39+
import { NavDrawerHierarchicalComponent } from './navdrawer/nav-drawer-hierarchical/nav-drawer-hierarchical.component';
3840

3941
@NgModule({
4042
declarations: [
@@ -51,7 +53,8 @@ import { NavbarCustomTitleComponent } from './navbar/navbar-custom-title/navbar-
5153
ActionStripParagraphComponent,
5254
ActionStripParagraphMenuComponent,
5355
ActionStripStylingComponent,
54-
NavbarCustomTitleComponent
56+
NavbarCustomTitleComponent,
57+
NavDrawerHierarchicalComponent
5558
],
5659
imports: [
5760
CommonModule,
@@ -67,7 +70,8 @@ import { NavbarCustomTitleComponent } from './navbar/navbar-custom-title/navbar-
6770
IgxRippleModule,
6871
IgxSwitchModule,
6972
IgxToggleModule,
70-
IgxNavbarModule
73+
IgxNavbarModule,
74+
IgxTreeModule
7175
]
7276
})
7377
export class MenusModule { }
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<div class="content-wrap" igxLayout>
2+
<igx-nav-drawer #drawer [isOpen]="true" [enableGestures]="true" width="280px">
3+
<ng-template igxDrawer>
4+
<igx-tree #tree>
5+
<igx-tree-node [data]="route.displayName" *ngFor="let route of routes">
6+
{{ route.displayName }}
7+
<igx-tree-node [data]="child.displayName" *ngFor="let child of route.children">
8+
<a igxTreeNodeLink [routerLink]="child.path">{{ child.displayName }}</a>
9+
</igx-tree-node>
10+
</igx-tree-node>
11+
</igx-tree>
12+
</ng-template>
13+
</igx-nav-drawer>
14+
15+
<main igxFlex>
16+
<span igxButton="icon" igxToggleAction="navigation" (click)="drawer.toggle()">
17+
<igx-icon family="material">menu</igx-icon>
18+
</span>
19+
<h5>{{selectedContent}}</h5>
20+
</main>
21+
</div>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.content-wrap {
2+
display: flex;
3+
height: 100%;
4+
}
5+
6+
main {
7+
height: 100%;
8+
overflow: auto;
9+
padding: 16px;
10+
}
11+
12+
:host {
13+
display: block;
14+
height: 100%;
15+
}

0 commit comments

Comments
 (0)