import { AfterContentInit , AfterViewInit , Component , ContentChildren , ElementRef , Input , OnDestroy , Optional , QueryList , Renderer2 , SkipSelf } from '@angular/core' ; import { NavigationEnd , Router , UrlTree } from '@angular/router' ; import { filter , takeUntil } from 'rxjs/operators' ; import { Subject } from 'rxjs' ; @ Component ( { selector : '[ux-navigation-item]' , templateUrl : './navigation-item.component.html' , host : { '[class.active]' : 'active' , '[class.selected]' : 'expanded' , } } ) export class NavigationItemComponent implements AfterViewInit , AfterContentInit , OnDestroy { /** The text to display in the navigation menu item. */ @ Input ( ) header : string ; /** The name of an icon from the UX Aspects icon set, to be displayed to the left of the title. */ @ Input ( ) icon : string ; /** Whether the navigation item is expanded, displaying the items from the `children` array. */ @ Input ( ) expanded : boolean = false ; /** The link that will be navigated to if this item is selected */ @ Input ( ) link : string ; /** Get the active state of this item from the router */ get active ( ) : boolean { return this . link ? this . _router . isActive ( this . link , true ) : false ; } /** Indicate the depth of the item */ _level : number ; /** Indicate whether the indentation should include the arrow */ _indentWithoutArrow : boolean = true ; @ ContentChildren ( NavigationItemComponent , { descendants : true } ) private _children : QueryList < NavigationItemComponent > ; get children ( ) : NavigationItemComponent [ ] { return this . _children . filter ( item => item !== this ) ; } /** Automatically unsubscribe when the component is destroyed */ private _onDestroy = new Subject < void > ( ) ; constructor ( private _elementRef , private _renderer , private _router , @ Optional ( ) @ SkipSelf ( ) private _parent ) { this . _level = this . _parent ? this . _parent . _level + 1 : 1 ; _router . events . pipe ( filter ( event => event instanceof NavigationEnd ) , takeUntil ( this . _onDestroy ) ) . subscribe ( ( ) => { this . expanded = this . hasActiveLink ( this . link ) ; } ) ; } ngAfterViewInit ( ) { const parentListElement = this . _elementRef . nativeElement . parentElement ; if ( parentListElement ) { const levelClass = this . getLevelClass ( ) ; if ( levelClass . length > 0 ) { this . _renderer . addClass ( parentListElement , 'nav' ) ; this . _renderer . addClass ( parentListElement , levelClass ) ; } } } ngAfterContentInit ( ) { this . setIndentWithoutArrow ( ) ; this . _children . changes . pipe ( takeUntil ( this . _onDestroy ) ) . subscribe ( ( ) => this . setIndentWithoutArrow ( ) ) ; } ngOnDestroy ( ) { this . _onDestroy . next ( ) ; this . _onDestroy . complete ( ) ; } /** Check if this item or any children are active */ private hasActiveLink ( link ) { if ( link && this . _router . isActive ( link , true ) ) { return true ; } return this . children . some ( item => item . hasActiveLink ( item . link ) ) ; } private getLevelClass ( ) { switch ( this . _level ) { case 2 : return 'nav-second-level' ; case 3 : return 'nav-third-level' ; case 4 : return 'nav-fourth-level' ; case 5 : return 'nav-fifth-level' ; } return '' ; } private setIndentWithoutArrow ( ) { if ( this . children . length > 0 ) { this . _indentWithoutArrow = false ; } else if ( this . _parent ) { this . _indentWithoutArrow = ! this . _parent . children . every ( ( item ) => item . children . length === 0 ) ; } else { this . _indentWithoutArrow = true ; } } }