Categories: Angular

How to build a custom collapsible sidebar navigation with Angular 6

Check out how to build a side navigation that fits perfectly into an admin layout or any dashboard page. We are going to create a simple collapsible sidenav that can be easily integrated into any Angular project that uses Bootstrap.

What we are going to build

Our goal is to create a collapsible sidenav. We want it to be hidden by default on smaller screens. You can see the component on the screenshot below:

The final project directory tree:

Requirements

I try to keep the project up to date. Visit the releases list to keep track of the current versions of frameworks and libraries used.
  • Angular CLI – a command line interface tool that generates projects, components, modules, services.
    I’m working on:
    $ ng --version
     
    Angular CLI: 6.0.8
    Node: 8.11.3
    OS: linux x64
    Angular: 6.1.1
  • The example app in this post uses the project available on my GitHub repo and described in the Enhance the presentation layer of your multi-layout Angular app post.
  • Bootstrap – version ^4.1.3.

Create a service

Generate the service for handling the menu toggle action:

$ ng generate service layout/authorised/services/authorised-side-nav

The service function is simple, it has a single parameter – hideSideNav – and changes its state every time the function toggleSideNav() is called. See the following code:

// src/app/layout/authorised/services/authorised-side-nav-service.ts
import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class AuthorisedSideNavService {
  hideSideNav: boolean = false;

  constructor() { }

  toggleSideNav(): void {
    this.hideSideNav = !this.hideSideNav;
  }
}

Create components

Top bar with the toggler

Let’s start with the top bar to create an elegant and functional frame for our dashboard:

$ ng generate component layout/authorised/authorised-top-nav

Replace the default content of the view with the following code:

<!-- src/app/layout/authorised/authorised-top-nav/authorised-top-nav.component.html -->
<nav class="navbar navbar-dark bg-dark">
  <app-authorised-side-nav-toggler></app-authorised-side-nav-toggler>
    <h3>keep_growing</h3>
</nav>

I’m including here the <app-authorised-side-nav-toggler> component so we need to add it to the project as well:

$ ng generate component layout/authorised/authorised-side-nav-toggler

And put this code in the template:

<!-- src/app/layout/authorised/authorised-side-nav-toggler/authorised-side-nav-toggler.component.html -->
<button  type="button" class="navbar-toggler" (click)="sideNavService.toggleSideNav()">
  <span class="navbar-toggler-icon"></span>
</button>

The toggler requires the AuthorisedSideNavService so we need to import it and inject to the component constructor:

// src/app/layout/authorised/authorised-side-nav-toggler/authorised-side-nav-toggler.component.ts
import { Component, OnInit } from '@angular/core';

import { AuthorisedSideNavService } from '../services/authorised-side-nav.service';

@Component({
  selector: 'app-authorised-side-nav-toggler',
  templateUrl: './authorised-side-nav-toggler.component.html',
  styleUrls: ['./authorised-side-nav-toggler.component.scss']
})
export class AuthorisedSideNavTogglerComponent implements OnInit {

  constructor(public sideNavService: AuthorisedSideNavService) { }

  ngOnInit() {
  }

}

To add those new components to the dashboard we need to include the top bar in our layout:

<!-- src/app/layout/authorised/authorised-layout/authorised-layout.component.html -->
<app-authorised-top-nav></app-authorised-top-nav>
<div class="wrapper">
  <app-authorised-side-nav></app-authorised-side-nav>
  <app-page-content></app-page-content>
</div>

The sidenav

Create the sidebar:

$ ng generate component layout/authorised/authorised-side-nav

The navigation also requires the AuthorisedSideNavService:

// src/app/layout/authorised/authorised-side-nav/authorised-side-nav.component.ts
import { Component, OnInit } from '@angular/core';
import { AuthorisedSideNavService } from '../services/authorised-side-nav.service';

@Component({
  selector: 'app-authorised-side-nav',
  templateUrl: './authorised-side-nav.component.html',
  styleUrls: ['./authorised-side-nav.component.scss']
})
export class AuthorisedSideNavComponent implements OnInit {

  constructor(public sideNavService: AuthorisedSideNavService) { }

  ngOnInit() {
  }

}

In the following code of the component template you can see how we are managing the visibility of the menu only by adding a conditional class to the template – the 'hidden' class:

<!-- src/main/angular/src/app/layout/authorised/authorised-side-nav/authorised-side-nav.component.html -->
<nav id="sidebar" class="navbar-dark bg-dark" [ngClass]="{'hidden': sideNavService.hideSideNav }">
  <ul class="navbar-nav">
    <li class="nav-item active">
      <a class="nav-link" href="#">Home page</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#">Link</a>
    </li>
    <li class="nav-item">
      <a class="nav-link" href="#">Link</a>
    </li>
  </ul>
</nav>

Add the following styling rules:

// src/app/layout/authorised/authorised-side-nav/authorised-side-nav.component.scss
:host {
background: #343a40;
}

#sidebar {
min-width: 200px;
max-width: 200px;
min-height: 100vh;
color: #fff;
transition: all 0.3s;
font-weight: 300;
font-size: 1rem;
line-height: 1.5;
}

#sidebar.hidden {
  margin-left: -200px;
}

a[data-toggle="collapse"] {
  position: relative;
}

@media (max-width: 575px) {
  #sidebar {
      margin-left: -200px;
  }
  #sidebar.hidden {
      margin-left: 0;
  }
}

a, a:hover, a:focus {
  color: inherit;
}

#sidebar .sidebar-header {
  padding: 20px;
}

#sidebar ul li a {
padding: 15px;
display: block;
width: 100%;
&:hover {
  background-color: rgba(255, 255, 255, 0.1);
}
}

hr {
border-top: 1px solid #fff;
margin-top: 0;
}

On a smaller screen the sidenav is hidden by default, you can still toggle its visibility by clicking the button on the top nav:

The work done in this section is contained in the commit 9300c12c207ba6f53eddbe2424a6aa33b8d629f7.

Fix the tests

Remember to include @Component in tests for components that contain other element:

//src/app/layout/authorised/authorised-top-nav/authorised-top-nav.component.spec.ts
…
import { Component } from '@angular/core';

@Component({selector: 'app-authorised-side-nav-toggler', template: ''})
class AuthorisedSideNavTogglerComponent {}
…
TestBed.configureTestingModule({
      declarations: [
        AuthorisedTopNavComponent,
        AuthorisedSideNavTogglerComponent
       ]
…
// src/app/layout/authorised/authorised-layout/authorised-layout.component.spec.ts
…
@Component({selector: 'app-authorised-top-nav', template: ''})
class AuthorisedTopNavComponent {}
…
beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AuthorisedLayoutComponent,
        AuthorisedSideNavComponent,
        AuthorisedTopNavComponent,
        PageContentComponent
      ]

The work done in this section is contained in the commit abd35eaeb9f689c5a84d3964c18bad789f57f43a.

Photo by Alice Moore on StockSnap

little_pinecone

View Comments

Share
Published by
little_pinecone

Recent Posts

Simplify the management of user roles in Spring Boot

Spring Security allows us to use role-based control to restrict access to API resources. However,…

3 years ago

Create a custom annotation to configure Spring Boot tests

A custom annotation in Spring Boot tests is an easy and flexible way to provide…

3 years ago

Keycloak with Spring Boot #4 – Simple guide for roles and authorities

Delegating user management to Keycloak allows us to better focus on meeting the business needs…

3 years ago

Keycloak with Spring Boot #3 – How to authorize requests in Swagger UI

Swagger offers various methods to authorize requests to our Keycloak secured API. I'll show you…

3 years ago

Keycloak with Spring Boot #2 – Spring Security instead of Keycloak in tests

Configuring our Spring Boot API to use Keycloak as an authentication and authorization server can…

3 years ago

Keycloak with Spring Boot #1 – Configure Spring Security with Keycloak

Keycloak provides simple integration with Spring applications. As a result, we can easily configure our…

3 years ago