I'm streaming

Angular 2 reusable modal service

I was recently working on an Angular 2 project that required a modal to be displayed to the end user. I decided to build a reusable component / service that can be injected into any other component and can manage the state of the modal.

To do so, I created a service that will control both the showing and hiding of the modal, as well as the current state.

modal/modal.service.ts

import {Injectable} from '@angular/core';
import { Subject } from 'rxjs';

@Injectable()
export class ModalService {
    isShowing = false;
    modal = new Subject();

    getModal() {
        return this.modal;
    }
    open() {
        this.isShowing = true;
        this.modal.next(true);
    }
    close() {
        this.isShowing = false;
        this.modal.next(false);
    }
    closeModal() {
        this.close();
    }
}

We can now associate our modal markup for this

modal/modal.component.html

<div class="fade in modal" [ngClass]="{'modal-open': modalOpen}">
    <div class="modal-dialog">
        Modal content and things
        <button class="btn btn-primary" (click)="closeModal($event)">Close</button>
    </div>
</div>

Now to actually make the modal work, we need to add our styles to work with our ngClass

modal/modal.component.scss

.modal {
  display: none;
  position: absolute;
  margin-top: 50%;
  top: -25%;
  right: 0;
  bottom: 0;
  left: 0;
  &-open {
    display: block;
  }
}

modal.component.ts

import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import {ModalService} from './modal.service';

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

  public modalOpen: boolean;

  constructor(private modalService: ModalService) { }

  ngOnInit() {

    this.modalService.getModal().subscribe((isOpen) => {
      this.modalOpen = isOpen as boolean;
    });
  }

  closeModal() {
    this.modalService.close();
  }
}

 

Inside of our desired components typescript file we can add now interact with our newly created service

test/test.component.ts

import { Component } from '@angular/core';
import { ModalService } from "../modal/modal.service";

@Component({
    selector: 'test-component',
    templateUrl: './test.component.html',
    styleUrls: ['./test.component.scss']
})

export class TestComponent {
    constructor(private modalService: ModalService) {}

    openModal() {
        this.modalService.open();
    }
}

Then inside of our markup we can add our code. this may be better to use the app-modal on the highest level html page like the app component to make sure it is consistent site wide. This example just uses it on a component.

test/test.component.html

<div class="row">
    <button (click)="openModal()">Open!</button>
</div>

<app-modal></app-modal>

 

Our app.module.ts will look something like this

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { ModalComponent } from './modal/modal.component';
import {ModalService} from './modal/modal.service';

@NgModule({
  declarations: [
    AppComponent,
    ModalComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [
    ModalService
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

You can checkout a zip of the code here ( not that it’s not styled, it just needs some love with how to actually show the modal. I used bootstrap when making this. )

angular-modal

An inventive, entrepreneurial and positively unsatisfied mind that constantly pushes the tech boundaries to create new solutions and devices that change people’s lives.

2 Comments
  1. Reply James March 28, 2018 at 10:11 am

    I followed your code – but once i click the button the modal is not showing up? I don’t see where you bind the modal component/service with the modal html…

    • Reply Jon Hemstreet March 28, 2018 at 10:50 am

      You are absolutely right, there is a missing piece of the modal.component.ts that should subscribe to the modal service. This component has a public variable on it called modalOpen. I’ll update this when I get some time in the next day or so!

Leave a Reply