ngx bootstrap open modal via routing

JDinar picture JDinar · Aug 29, 2018 · Viewed 7.1k times · Source

I have a ngx bootstrap modal that currently works and opens a Details Listing page with specific data for everyone of my Listings. However I would like to use routing so that my Listing Modal can be opened via direct url and populated with listing specific details based on it's id. For example .../listings/listing/50 would open the Listing Modal and be populated with the details for listing id 50.

I can't even get any modal to open via direct url at this time.

Currently I am opening each modal with a link click

<a (click)="openDetailsModal(listing)" ...

and my ListingService

  openDetailsModal(listing: Listing): void {
    this.selectedListing = listing;
    this.bsModalRef = this.modalService.show(ListingDetailComponent, {class:'listingDetailModal'});
    this.bsModalRef.content.listing = this.selectedListing;
  }

Also I am currently getting all of my listings from my database as well using HttpClient

Answer

Joel Richman picture Joel Richman · Aug 30, 2018

You can use the standard bootstrap modal in this scenario. Add the modal markup to your component and then load it via routing. I've added the "show" class to the modal so that it will display right away. Make sure you have a router-outlet on your parent component. Here is a demo on Stackblitz.

Your listing modal component would look like this:

import { Component, Input, Output, EventEmitter, AfterViewInit } from '@angular/core';
import { Router } from '@angular/router';

@Component({
    selector: 'listing-dialog',
    template: `
    <div id="backdrop" class="modal-backdrop fade" [ngClass]="{ show: showModal }"></div>
    <div class="modal d-block fade" 
      [ngClass]="{ show: showModal }"
      (click)="onClose()"
      id="listing-dialog" 
      tabindex="-1" role="dialog" aria-labelledby="modalIdLabel">
        <div class="modal-dialog" role="document" (click)="onDialogClick($event)">
            <div class="modal-content">
                <div class="modal-header">
                    <h5>I was loaded via route</h5>
                    <button type="button"
                        class="close"
                        (click)="onClose()"
                        aria-label="Close"><span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                  <p>Add some detail here.</p>
                </div>
                <div class="modal-footer">
                  <button type="button" class="btn btn-primary" (click)="onClose()">Close</button>
                </div>
            </div>
        </div>
    </div>
    `
})
export class ListingDialogComponent implements AfterViewInit {

    showModal = false;

    constructor(private router: Router) { }

    ngAfterViewInit() {
      this.showModal = true;
    }

    onClose() {
      this.showModal = false;
      //Allow fade out animation to play before navigating back
      setTimeout(
        () => this.router.navigate(['..']),
        100
      );
    }

    onDialogClick(event: UIEvent) {
      // Capture click on dialog and prevent it from bubbling to the modal background.
      event.stopPropagation();
      event.cancelBubble = true;
    }
}

Your hosting component would have something like this:

<a [routerLink]="['listing']" >Load Listing</a>
<router-outlet></router-outlet>

The module would need to register the routes:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { Routes, RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { HelloComponent } from './hello.component';
import { ListingDialogComponent } from './listing-dialog.component';

const routes: Routes = [
  { path: 'listing', component: ListingDialogComponent }
]

@NgModule({
  imports:      [ BrowserModule, FormsModule, RouterModule.forRoot(routes) ],
  declarations: [ AppComponent, HelloComponent, ListingDialogComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

I did not include parameters in the demo, but you can easily observe them in the modal and then perform any necessary service calls to populate the modal. I use this method in many places in my apps.