Angular Material: Constructing a Powerful Frontend App with Material Design

The conclusion of our protests map series is here! This series began with an introduction to the background and architecture of the project, followed by detailed information on the lower-level details and specifications. We then moved on to implementing observables streaming and Firebase Authentication. Now, we are ready to use the Angular Material library to bring our layout to life.

Table of Contents

Add Angular Material

Just as we ran the ng add @angular/fire command the Angular CLI will take you through the material setup by running the following command:

ng add @angular/material

Use the default suggestions by the CLI, so the result should look something like this:

ng add @angular/material

Generate the Layout Module

Once we have @angular/material installed, we can start building our layout components. Run the following command:

ng g m layout

Now let’s import the material’s components that we want to use, and edit the layout.module.ts file as follows:

import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatListModule } from '@angular/material/list';
import { MatMenuModule } from '@angular/material/menu';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatToolbarModule } from '@angular/material/toolbar';
import { NgModule } from '@angular/core';

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    MatSnackBarModule,
    MatMenuModule,
    MatListModule,
    MatSidenavModule,
    MatToolbarModule,
    MatButtonModule,
    MatIconModule,
  ],
})
export class LayoutModule {}

Create Angular Material Navbar Component

Use the Angular CLI to generate a new component named `navbar`.

ng g c --skip-tests=true layout/navbar

Before we start editing our navbar component, on the layout/layout.module.ts file, right after the imports array, add the exports array with navbar components:

...
imports: [
    ...
  ],
  exports: [NavbarComponent],
...
   

This will allow us later to import the navbar component to our AppModule.

Open the navbar component class file and edit it as follows:

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

import { Observable } from 'rxjs';
import { UserService } from 'src/app/user/user.service';

@Component({
  selector: 'app-navbar',
  templateUrl: './navbar.component.html',
  styleUrls: ['./navbar.component.scss'],
})
export class NavbarComponent implements OnInit {
  isLoggedIn$?: Observable<boolean>;
  constructor(private userService: UserService) {}

  ngOnInit(): void {
    this.isLoggedIn$ = this.userService.isLoggedIn$;
  }

  signOut() {
    this.userService.signOut();
  }
}

Write the Template

Edit the navbar.component.html so it looks like this:

<mat-drawer-container class="toolbar">
  <div class="navbar-container">
    <mat-toolbar color="primary" class="navbar">
      <div class="navbar-items">
        <button mat-icon-button (click)="sidenav.toggle()">
          <mat-icon>menu</mat-icon>
        </button>
        <a class="logo" href="/">Protests Map</a>
        <div class="sign-out" *ngIf="isLoggedIn$ | async">
          <a color="accent" (click)="signOut()" matTooltip="Log out">
            <mat-icon>logout</mat-icon>
          </a>
        </div>
        <div *ngIf="(isLoggedIn$ | async) === false">
          <button mat-icon-button [matMenuTriggerFor]="help">
            <mat-icon class="more-vert">more_vert</mat-icon>
          </button>
        </div>
      </div>
      <div>
        <mat-menu #help="matMenu">
          <button mat-menu-item>Help</button>
          <button mat-menu-item>FAQ</button>
        </mat-menu>
      </div>
    </mat-toolbar>
    <span class="spacer"></span>
  </div>
</mat-drawer-container>
<mat-drawer #sidenav class="sidenav" mode="push">
  <mat-nav-list>
    <mat-list-item></mat-list-item>
    <mat-list-item>
      <a
        mat-list-item
        *ngIf="(isLoggedIn$ | async) === false; else hoistBlock"
        (click)="sidenav.toggle()"
        href="signin"
      >
        Sign In
      </a>
      <ng-template (click)="sidenav.toggle()" #hoistBlock>
        <a mat-list-item href="/">Hoist a flag</a>
      </ng-template>
    </mat-list-item>
    <mat-list-item>
      <a
        mat-list-item
        *ngIf="(isLoggedIn$ | async) === false; else flagsBlock"
        (click)="sidenav.toggle()"
        href="signup"
      >
        Sign Up
      </a>
      <ng-template (click)="sidenav.toggle()" #flagsBlock>
        <a mat-list-item href="flags">Flags</a>
      </ng-template>
    </mat-list-item>
    <mat-list-item>
      <a mat-list-item (click)="sidenav.toggle()" mat-list-item>Close</a>
    </mat-list-item>
  </mat-nav-list>
</mat-drawer>

Before we import our navbar into our app component, let’s add some style. Open the navbar.component.scss and the following CSS to it.

.toolbar {
  position: sticky;
  position: -webkit-sticky;
  top: 0;
  z-index: 1000;
}

.navbar-container {
  display: flex;
  color: #5F7BAE;
}

.logo {
  position: center;
  color: white;
}

.navbar-items {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

That’s it, our navbar is ready to use.

Import the Navbar Component

Open the app.module.ts file, import the LayoutModule and add it to the imports array.

import { LayoutModule } from './layout/layout.module';

...
imports: [
    ...
    LayoutModule,
  ],
...   

Add the navbar tag to the app component template, so your app.component.html should look like this:

<html>
  <app-navbar></app-navbar>
  <router-outlet></router-outlet>
</html>
Angular Material Navbar Component

Conclusion

The rest of the Protests Map application code can be found on the GitHub repository. Most of the things are just other components similar to what we have already seen through this tutorial, there is one exception which is the icon registry, a class that enables the usage of custom SVG icons inside the <mat-icon> tag.

It is true that Angular, compare to other frontend libraries/frameworks, has a greater learning curve. But it comes also with the fact that Angular is more than a library. You can build a whole MVP application using the Angular framework and its official APIs.

chevron_left
chevron_right

Leave a comment

Your email address will not be published. Required fields are marked *

Comment
Name
Email
Website