1

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>
surjendu_dey
  • 578
  • 2
  • 11
  • 28
  • Try using regex pattern to match patterns to determine whether to hide or show routes OR Use a service that holds information to determine hiding/showing and subscribe to them in every component that needs this feature. – Nicholas K Dec 19 '20 at 10:41

2 Answers2

2

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);
}
Some random IT boy
  • 7,569
  • 2
  • 21
  • 47
  • is there a way I can use just shouldShowNavBar(url) method and exclude the async functions? if so how can I call it in my template with *ngIf and how to catch the current url in my ngOnInit() – surjendu_dey Dec 19 '20 at 11:31
  • Technically you shoud be able to call ```
    ``` with the current setup you had
    – Some random IT boy Dec 19 '20 at 11:39
  • in doing so it's returning Cannot read property 'includes' of undefined. It seems url.includes/startsWith is coming as undefined – surjendu_dey Dec 19 '20 at 11:48
  • because there's a moment where the `url` is not set yet because the subscribe callback hasnt been activated yet. You should add this at the beggining of the function ```if(!url) return false;``` – Some random IT boy Dec 19 '20 at 11:50
  • Or initialise the `url` property with some value that makes sense to you – Some random IT boy Dec 19 '20 at 11:51
  • inside which function should I be adding `if(!url) return false;` Please give a bit more info because using async becomes a bit complicated for me – surjendu_dey Dec 19 '20 at 11:54
  • the approach is working when there is just condition inside the [ ] . Adding multiple URL like `!url.include('/admin/dashboard'), !url.incude('/admin/category/:categoryId'),` is not working – surjendu_dey Dec 19 '20 at 12:24
  • 1
    change `some` for `every` if you want to do an AND with all the conditions. Do `some` if you want an OR – Some random IT boy Dec 19 '20 at 14:08
  • I get you..but the actual problem still remains for dynamic routes such as `/admin/category/:categoryId` – surjendu_dey Dec 19 '20 at 14:47
  • 1
    Your dynamic routes will all start with `/admin/category` and then will follow up with `/123` or whatever ID. So with those you can just do `url.startsWith('/admin/category')` and you will match all of the paths that start with `/admin/category`. If you have some complex URL I suggest using regular expressions which you have some examples with my code and you also have the link to the documentation on how to use them. – Some random IT boy Dec 19 '20 at 15:01
1

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';

@Component({
  selector: 'my-component',
  templateUrl: './my.component.html',
  styleUrls: ['./my.component.scss']
})
export class MyComponent implements OnInit {

  constructor(
    private router: Router,
  ) {}

  ngOnInit() {
  }


  /**
   * Check if the router url contains the specified route
   *
   * @param {string} route
   * @returns
   * @memberof MyComponent
   */
  hasRoute(route: string) {
    return this.router.url.includes(route);
  }
}
<!-- First view -->
<div *ngIf="hasRoute('home')">
    First View
</div>

<!-- Second view activated when the route doesn't contain the home route -->
<div *ngIf="!hasRoute('home')">
    Second View
</div>
  • 1
    Please provide explanation for your answers, so others can benefit from it. – rcanpahali Sep 15 '21 at 12:09
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-ask). – Community Sep 15 '21 at 14:08