Skip to content

Commit

Permalink
feat(menu): add support for subMenuComponent
Browse files Browse the repository at this point in the history
And fix visibility controls via configuration
  • Loading branch information
Alex Malkevich committed Feb 27, 2019
1 parent a9600a3 commit e5fb388
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 13 deletions.
24 changes: 20 additions & 4 deletions projects/dynamic-menu/src/lib/dynamic-menu.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ export class DynamicMenuService {
return this.dynamicMenu$;
}

isActive(fullPath: string[], exact = false) {
return this.router.isActive(this.router.createUrlTree(fullPath), exact);
}

private getDynamicMenuRoutes() {
return this.injector
.get(DYNAMIC_MENU_ROUTES_TOKEN, [])
Expand All @@ -66,18 +70,25 @@ export class DynamicMenuService {
}

private resolveSubMenuComponent(
config: DynamicMenuRouteConfig,
config: RouteWithMenu,
subMenuMap: SubMenuMap[],
) {
if (!config.data || !config.data.menu) {
return '';
return;
}

const name = config.data.menu.subMenuComponent;

if (typeof name === 'string') {
const info = subMenuMap.find(m => m.name === name);
return info ? info.type : name;

if (!info) {
console.warn(`DynamicMenuService: Could not resolve sub-menu component string ${name}!
Please make sure to provide mapping via 'DynamicMenuModule.provideSubMenu()'`);
return;
}

return info.type;
}

return name;
Expand All @@ -95,11 +106,16 @@ export class DynamicMenuService {
const path = parentConfig
? parentConfig.fullUrl || [parentConfig.path]
: [];

config.data.menu.subMenuComponent = this.resolveSubMenuComponent(
config,
subMenuMap,
);

return {
...config,
// tslint:disable-next-line: no-non-null-assertion
fullUrl: [...path, config.path!].filter(p => p != null),
subMenuComponent: this.resolveSubMenuComponent(config, subMenuMap),
};
});
}
Expand Down
2 changes: 1 addition & 1 deletion projects/dynamic-menu/src/lib/dynamic-menu/context-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ export class DynamicMenuItemContext extends DynamicMenuTemplateContext {
public $implicit: DynamicMenuRouteConfig,
tpl: TemplateRef<any>,
) {
super(tpl, { $implicit: $implicit.data.menu.children });
super(tpl, { $implicit: $implicit.data.menu.children }, $implicit);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import { TemplateRef } from '@angular/core';

import { DynamicMenuRouteConfig } from '../types';

export class DynamicMenuTemplateContext {
constructor(
/** Reference to template with children items */
public tpl: TemplateRef<any>,
/** Context for {@link TemplateRef} `tpl` */
public ctx: any,
/**
* @internal
* Parent route config to determine if template should be rendered
*/
public parentConfig?: DynamicMenuRouteConfig,
) {}
}
2 changes: 2 additions & 0 deletions projects/dynamic-menu/src/lib/dynamic-menu/context-toggle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ export class DynamicMenuToggleContext extends DynamicMenuItemContext {
/** Every computed route config */
$implicit: DynamicMenuRouteConfig,
tpl: TemplateRef<any>,
opened: boolean = false,
) {
super($implicit, tpl);
this.context.opened = opened;
}
}
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
<ng-container *ngTemplateOutlet="ctx?.tpl; context: ctx?.ctx"></ng-container>
<ng-container *ngIf="(shouldRender$ | async)">
<ng-container
*ngComponentOutlet="ctx?.parentConfig?.data?.menu?.subMenuComponent"
></ng-container>
<ng-container *ngTemplateOutlet="ctx?.tpl; context: ctx?.ctx"></ng-container>
</ng-container>
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import {
OnInit,
ViewContainerRef,
} from '@angular/core';
import { NavigationEnd, Router } from '@angular/router';
import { filter, map, startWith } from 'rxjs/operators';

import { DynamicMenuService } from '../../dynamic-menu.service';
import { DynamicMenuTemplateContext } from '../context-template';

export interface NgView<T, C = T> {
Expand All @@ -22,7 +25,20 @@ export interface NgView<T, C = T> {
export class DynamicMenuItemsComponent implements OnInit {
ctx: DynamicMenuTemplateContext | undefined;

constructor(private vcr: ViewContainerRef) {}
navigationEnd$ = this.router.events.pipe(
filter(e => e instanceof NavigationEnd),
);

shouldRender$ = this.navigationEnd$.pipe(
startWith(null),
map(() => this.shouldRender()),
);

constructor(
private vcr: ViewContainerRef,
private dynamicMenuService: DynamicMenuService,
private router: Router,
) {}

ngOnInit(): void {
this.ctx = this.getTplContext((this.vcr as any)._view);
Expand All @@ -41,4 +57,35 @@ export class DynamicMenuItemsComponent implements OnInit {
view = view.parent;
}
}

private shouldRender() {
if (!this.ctx) {
return false;
}

const { parentConfig } = this.ctx;

if (parentConfig) {
const {
renderAsToggle,
showChildrenIfActivated,
showChildrenIfChildActivated,
} = parentConfig.data.menu;

if (renderAsToggle) {
return true;
}

if (showChildrenIfActivated) {
return this.dynamicMenuService.isActive(parentConfig.fullUrl);
} else if (showChildrenIfChildActivated) {
return (
!this.dynamicMenuService.isActive(parentConfig.fullUrl, true) &&
this.dynamicMenuService.isActive(parentConfig.fullUrl)
);
}
}

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ export class DynamicMenuComponent implements OnInit, OnDestroy {
}

getToggleCtx(config: DynamicMenuRouteConfig, tpl: TemplateRef<any>) {
return this.getCtx(config, () => new DynamicMenuToggleContext(config, tpl));
return this.getCtx(config, () => {
const opened = this.dynamicMenuService.isActive(config.fullUrl);
return new DynamicMenuToggleContext(config, tpl, opened);
});
}

private getCtx<T>(key: any, factory: () => T): T {
Expand Down
6 changes: 1 addition & 5 deletions projects/dynamic-menu/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ export interface MenuItem {
* Icon for menu item
*/
icon?: string;
/**
* Make item not a navigation link but only reveal it's children links
*/
justToggleChildren?: true;
/**
* Only show children items if route is being activated
*/
Expand Down Expand Up @@ -46,6 +42,7 @@ export interface RouteWithMenu extends Route {
export interface RoutesWithMenu extends Array<RouteWithMenu> {}

export interface DynamicMenuItem extends MenuItem {
subMenuComponent?: Type<any>;
children: DynamicMenuRouteConfig[];
}

Expand All @@ -56,7 +53,6 @@ export interface DynamicDataWithMenu extends DataWithMenu {
export interface DynamicMenuRouteConfig extends RouteWithMenu {
data: DynamicDataWithMenu;
fullUrl: string[];
subMenuComponent?: Type<any> | string;
}

export type DynamicMenuConfigFn = (
Expand Down

0 comments on commit e5fb388

Please sign in to comment.