The Protests Map Part V – Angular Material Components

The following post is the last post of the protests map series, the previous posts in this series were:

Next, we will implement our layout using the Angular Material library. Angular Material is a library built and maintained by the Angular team, it provides common UI components and tools that help you customize your own components based on Material Design.

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, 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 the 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 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>
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 enable 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.

Comment
Name
Email
Website