Ok, I gave it try myself.
Again, not sure if this is a best practice approach, but perhaps a start. At a minimum I hope to trigger some good discussion. With that said, it was probably just fair to attempt it myself first.
In the CLASS part you see that I’m directly accessing the SHARED pages data object, one of the questions:
Q1 Does direct access limit me in any way (later on)?
Q2 Would a Event/Subscribe model be more useful / appropriate?
HTML (part of sidebar template)
<ion-list>
<ion-list-header>Nav Menu</ion-list-header>
<button menuClose ion-item *ngFor="let page of pages" (click)="openPage(page)" [trackNav]="page">
<ion-icon name="{{page.icon}}" item-left></ion-icon>
<ion-label fixed>{{page.title}}</ion-label>
<ion-badge item-right color="secondary" [hidden]="page.badge < 1">{{page.badge}}</ion-badge>
</button>
</ion-list>
DIRECTIVE (trackNav)
@Directive({ selector: '[trackNav]' })
export class NavActiveDirective {
@Input('trackNav') targetPage;
constructor(
private _appCtrl: App,
private _element: ElementRef,
private _renderer: Renderer
) {
// Nothing to do yet
}
ngOnInit() {
this._appCtrl.getRootNav().viewDidEnter.subscribe(
(view) => {
this.checkActive(view);
}
)
}
ngAfterViewInit() {
this.checkActive(null);
}
checkActive(view) {
let active = (view && view.component === this.targetPage.component)?true:false; // isActive link
this._renderer.setElementClass(this._element.nativeElement, 'nav-link-active', active);
}
}
CLASS (sidebar controller)
@Component({
selector: 'left-sidebar',
templateUrl: 'left-sidebar.html'
})
export class LeftSidebarComponent {
public pages: Array<IPageNav>;
constructor(
private _appCtrl: App,
public menuNavCtrl: MenuNavService,
) {
this.pages = this.menuNavCtrl.pages;
// ^^^ debatable if direct access or a subscription model is more useful
}
public openPage(page) {
if (page && page.component != this._appCtrl.getRootNav().getActive().component)
this._appCtrl.getRootNav().setRoot(page.component);
}
}
SHARED SERVICE (nav tracking & badge ctrl class)
export interface IPageNav {
title: string;
component: any;
badge: number;
icon: string;
}
@Injectable()
export class MenuNavService {
public pages: Array<IPageNav>;
constructor( @Inject(DemoDataService) private _ddService: IDemoDataService) {
//
}
public fetchPageObject(pageTitle: string): any {
for (var i = this.pages.length - 1; i >= 0; i--) {
if (this.pages[i].title === pageTitle)
return this.pages[i];
}
return null;
}
public incrementBadge(pageTitle: string): void {
let pageObject = this.fetchPageObject(pageTitle);
pageObject && pageObject.badge++;
}
public decrementBadge(pageTitle: string): void {
let pageObject = this.fetchPageObject(pageTitle);
pageObject && pageObject.badge--;
if (pageObject && pageObject.badge < 0)
pageObject.badge = 0;
}
public resetBadge(pageTitle: string): void {
let pageObject = this.fetchPageObject(pageTitle);
pageObject && (pageObject.badge = 0);
}
public getAllPages(): Array<IPageNav> {
return this.pages;
}
public setPages(pages: Array<IPageNav>): void {
this.pages = pages;
}
}
EDIT: here is the initial PAGES object init, in app.components:
this.menuNavCtrl.setPages([
{ title: 'Page One', component: Page1Page, badge: 0, icon: 'some-icon' },
{ title: 'Page Two', component: Page2Page, badge: 1, icon: 'some-other-icon' }
]);