Angular – Bottom Sheet

Photo by Karolina Grabowska from Pexels

Overview

This is a short example of Angular Material Bottom Sheet passing data and displaying a list of items from another component inside the bottom sheet. The text from the Input field appears in the top of the bottom sheet. Usually an ID or information relevant to the page will be displayed.

Source Files

Get Source Code

Create a New Angular Application

First, create a new application

ng new my-app

Once the application has been created CD into the new application folder.

cd my-app

Install Material with Angular Schematics – “ng add”. This will take care of installing Material and it dependencies and basic configuration. You will still need to take care of the imports which is discussed in the next section.

ng add @angular/material

Create the following components

ng g c components/bottom-sheet-demo/parent-bottom-sheet-layout
ng g c components/bottom-sheet-demo/data-table

In the “app.module.html” remove the default generated content and just place the parent-layout-component.

<app-parent-bottom-sheet-layout ></app-parent-bottom-sheet-layout>

Material Module

Because there are a lot of imports to using Material, most examples I have seen use a separate module to handle these imports. Below is a step by step on creating the module and adding it to the root module “app.module.ts”.

Create a new module labeled “material.module.ts“. Link to article on how to do this.

Make sure you have the following imports in your “apps.module.ts” file.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientJsonpModule, HttpClientModule } from '@angular/common/http';
import { MaterialModule } from './material.module';

@NgModule({
  declarations: [
    AppComponent,
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    ReactiveFormsModule,
    BrowserAnimationsModule,
    HttpClientModule,
    HttpClientJsonpModule,
    BrowserAnimationsModule,
    FormsModule,    
    MaterialModule
  ],
  providers: [],
  entryComponents: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

You can learn more about this from material.angular.io.

Create or choose an existing component to add the bottom sheet to.

Add the imports needed to the Root “app.module.ts” or Feature Module.

Add the imports needed to the Root or Feature Module.

import { MatBottomSheet } from '@angular/material/bottom-sheet';
....
@NgModule({
 declarations: [],
 imports: [
    MatBottomSheet,
....

Parent Component

The parent component in this application will have a an entry component for the bottom sheet and a data table component for the bottom sheet.

Text from the input field will be passed to the bottom sheet entry component.

Add the import to the component.

import { MatBottomSheet, MatBottomSheetRef, MAT_BOTTOM_SHEET_DATA } from '@angular/material/bottom-sheet';

TypescriptComponent Body

The MatBottomSheet and FormBuilder are declared in the constructor. This example uses a small single control (input) reactive form. You can read more about reactive forms here. Using a form builder for a small form like this is an overkill but once you start using Form Builder, you will want to use it everywhere. 🙂

 constructor(private _bottomSheet: MatBottomSheet, private fb: FormBuilder) { }
  
 public parentForm = this.fb.group({
   title: [null, Validators.required],
 });

 openBottomSheet(): void {
   const bottomSheetRef = this._bottomSheet.open(DemoBottomSheet, {
     data: { title: this.parentForm.get('title').value }
   });
 }

Entry Component – Bottom Sheet

Add Bottom Sheet Component after the main parent layout component

import { Component, OnInit, Input, OnDestroy} from '@angular/core';
// All Imports

@Component({
  selector: 'parent-component',
  templateUrl: './parent-component.component.html',
  styleUrls: ['./parent-component.component.scss']
})
export class LandsideSectionComponent implements OnInit, OnChanges {
// Code 
 openBottomSheet(): void {
    this._bottomSheet.open(BottomSheetLandsidePeekDays, {
      data: { data: this.data }
    });
  }
}

@Component({
  selector: 'my-bottom-sheet',
  templateUrl: 'demo-bottom-sheet.html',
  styleUrls: ['./demo-bottom-sheet.scss']
})
export class MyBottomSheet {

  constructor(@Inject(MAT_BOTTOM_SHEET_DATA) public data: any,
              private _bottomSheetRef: MatBottomSheetRef<MybottomSheet>, ) {}

  users =  this.data;
  openLink(event: MouseEvent): void {
    this._bottomSheetRef.dismiss();
    event.preventDefault();
  }
}

HTMLParent Component

The example from GitHub uses Material Grid and Cards. They were left out to just keep it simple.


<form [formGroup]="parentForm" novalidate autocomplete="off">

  <mat-form-field appearance="fill">
    <mat-label>Input</mat-label>
    <input matInput formControlName="title">
  </mat-form-field>
            
  <button mat-raised-button color="primary" class="openBtn" id="openBtn" (click)="openBottomSheet()" [disabled]="!parentForm.valid">Open Bottom Sheet</button>
 </form>
        

Bottom Sheet – Entry Component

Create a file labeled “demo-bottom-sheet.html” in the folder as the parent component. The “demo-bottom-sheet.scss” is optional but it is imported in the @Component decorator for this example.

HTML – Bottom Sheet Entry Component

<mat-nav-list>
  <h5>{{data.title}}</h5>
  <div class="scrollbar-table" id="style-red">
    <mat-list-item *ngFor="let user of users"> {{user}} </mat-list-item>
  <span mat-line>&nbsp;</span>
  <span mat-line>&nbsp;</span>
  <span mat-line>&nbsp;</span>
 </div>
</mat-nav-list>