Search code examples
javascriptangularangular-routingangular-componentsangular-activatedroute

hide component in Angular in certain dynamic route


I need to hide certain components from my main home page like the navbar and footer when I'm logged in to my admin panel. My admin components are lazy-loaded based on an admin module when called. The necessary components are getting hidden as expected when on admin view if the routes are not dynamic i.e like /admin/login, /admin/dashboard etc. But the problem starts if the routes are dynamic like /admin/category/:categoryId or /admin/user/:userId and in these routes the necessary components like navbar and footer doesn't hide itself. I'm getting the dynamic ids for the routes using ActivatedRoute in the necessary components. Below is the method I'm using on my main page to read the application routes and show/hide components accordingly.

Main.ts

 import { Router, NavigationEnd } from '@angular/router';

  public url: any;

  constructor(private router: Router) {

    this.router.events.subscribe((event) => {
      if (event instanceof NavigationEnd) {
        this.url = event.url;
      }
    })
  }

Main.html

<div class="main__container">
  <app-navbar
    *ngIf="url !== '/admin' && url !== '/admin/dashboard' && url !== '/admin/post-article' && url !== '/admin/video' && url !== '/admin/login' && url !== '/admin/sign-up' && url !== '/admin/category/:categoryId'">
  </app-navbar>
  <app-footer
    *ngIf="url !== '/admin' && url !== '/admin/dashboard' && url !== '/admin/category/:categoryId' && url !== '/admin/post-article' && url !== '/admin/video' && url !== '/admin/login' && url !== '/admin/sign-up'">
  </app-footer>
</div>

Solution

  • What you need here is to define regular expressions and test against those. Or maybe it's enough for you to check the string#includes(string) function. I would also suggest to use a more reactive (rxjs like) approach.

    On my template I would have:

    
    <div class="main__container">
      <app-navbar *ngIf="canShowNavBar$ | async">
      </app-navbar>
      <app-footer *ngIf="canShowFooter$ | async">
      </app-footer>
    </div>
    
    

    Where on the typescript file I would have:

    export class YourComponent implements OnInit {
    
       canShowNavBar$: Observable<boolean>;
       canShowFooter$: Observable<boolean>;
       navigationEvents$: Observable<NavigationEnd>;
    
    
       constructor(private router: Router){}
    
       ngOnInit() {
         // Like this we define the stream of the NavigationEnd events
         this.navigationEvents$ = this.router.events.pipe(
            filter(event => event instanceof NavigationEnd),
            // This one is not really needed but we're giving some hints to the typescript compiler
            map(event => event as NavigationEnd) 
          );
          // Here we define the stream of booleans that determine whether to show the component or not on your template.
          this.canShowNavBar$ = this.navigationEvents$.pipe(
             map(event => this.shouldShowNavBar(event.url))
          );
          // Because actually you check for the same conditions
          this.canShowFooter$ = this.canShowNavBar$;
       }
    
       shouldShowNavBar(url: string): boolean {
          // And here you should test against regular expressions:
         switch(true) {
            case /\/admin\/dashboard/.test(url):
            case /\/admin\/category/.test(url):
            // More cases where you should show the navBar
               return true;
            default: return false;
         }
    
    
    
       }
       
    }
    

    You can read more about Regular Expressions on JavaScript here

    Another approach of implementing the shouldShowNavBar would be using some array predicates like some: Like so:

    
    shouldShowNavBar(url: string): boolean {
       const conditions = [
          !url.startsWith('/admin/dashboard'),
          !url.includes('/admin/category'),
          // More conditions?
       ];
       return conditions.some(isTrue => isTrue);
    }
    
    

    If you don't want to use the async keep your code as it was but do:

    
    <div class="main__container">
      <app-navbar *ngIf="shouldDisplayNavBar(url)">
      </app-navbar>
      <app-footer *ngIf="shouldDisplayNavBar(url)">
      </app-footer>
    </div>
    
    
    
    shouldShowNavBar(url: string): boolean {
       if(!url) {
         return false;
       }
    
       const conditions = [
          !url.startsWith('/admin/dashboard'),
          !url.includes('/admin/category'),
          // More conditions?
       ];
       return conditions.some(isTrue => isTrue);
    }