dougludlow / ng2-bs3-modal

Angular Bootstrap 3 Modal Component
http://dougludlow.github.io/ng2-bs3-modal/
ISC License
261 stars 133 forks source link
angular angular-component angular2 modal ng2-bs3-modal

ng2-bs3-modal npm version npm downloads Build Status

Angular (2+) Bootstrap 3 Modal Component

Demo

http://dougludlow.github.io/ng2-bs3-modal/

Dependencies

ng2-bs3-modal depends on bootstrap which depends on jquery. You'll need to include both scripts before ng2-bs3-modal or somehow make them available globally, depending on your build system. Example:

npm install jquery bootstrap@^3.3.7

./jquery.ts

import * as $ from 'jquery';
window['jQuery'] = window['$'] = $;

./main.ts

import './jquery';
import 'bootstrap/js/modal'; // or just 'bootstrap'
import 'bootstrap/dist/css/bootstrap.css'; // optional

Install

npm

npm install --save ng2-bs3-modal

yarn

yarn add ng2-bs3-modal

Then include the module in the imports collection of your app's module:

import { NgModule } from '@angular/core';
import { BsModalModule } from 'ng2-bs3-modal';

@NgModule({
    imports: [ BsModalModule ]
    ...
})
export class MyAppModule { }

API

BsModalComponent

Inputs

Outputs

Methods

BsModalHeaderComponent

Inputs

BsModalFooterComponent

Inputs

BsModalService

Methods

Example Usage

Default modal

<button type="button" class="btn btn-default" (click)="modal.open()">Open me!</button>

<bs-modal #modal>
    <bs-modal-header [showDismiss]="true">
        <h4 class="modal-title">I'm a modal!</h4>
    </bs-modal-header>
    <bs-modal-body>
        Hello World!
    </bs-modal-body>
    <bs-modal-footer [showDefaultButtons]="true"></bs-modal-footer>
</bs-modal>

Example

Static modal

This will create a modal that cannot be closed with the escape key or by clicking outside of the modal.

<bs-modal #modal [keyboard]="false" [backdrop]="'static'">
    <bs-modal-header [showDismiss]="false">
        <h4 class="modal-title">I'm a modal!</h4>
    </bs-modal-header>
    <bs-modal-body>
        Hello World!
    </bs-modal-body>
    <bs-modal-footer [showDefaultButtons]="true"></bs-modal-footer>
</bs-modal>

Use custom buttons in footer

<bs-modal #modal>
    <bs-modal-header>
        <h4 class="modal-title">I'm a modal!</h4>
    </bs-modal-header>
    <bs-modal-body>
        Hello World!
    </bs-modal-body>
    <bs-modal-footer>
        <button type="button" class="btn btn-default" data-dismiss="modal" (click)="modal.dismiss()">Cancel</button>
        <button type="button" class="btn btn-primary" (click)="modal.close()">Ok</button>
    </bs-modal-footer>
</bs-modal>

Example

Opening and closing the modal from a parent component

import { Component, ViewChild } from '@angular/core';
import { BsModalComponent } from 'ng2-bs3-modal';

@Component({
    selector: 'parent-component',
    template: `
        <bs-modal #myModal>
            ...
        </bs-modal>
    `
})
export class ParentComponent {
    @ViewChild('myModal')
    modal: BsModalComponent;

    close() {
        this.modal.close();
    }

    open() {
        this.modal.open();
    }
}

Opening the modal when the parent component loads

import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { BsModalComponent } from 'ng2-bs3-modal';

@Component({
    selector: 'parent-component',
    template: `
        <bs-modal #myModal>
            ...
        </bs-modal>
    `
})
export class ParentComponent implements AfterViewInit {
    @ViewChild('myModal')
    modal: BsModalComponent;

    ngAfterViewInit() {
        this.modal.open();
    }
}

Note: ViewChild doesn't resolve the modal property until AfterViewInit. OnInit is too early and will result in an "undefined" error.

Multiple modals in a component

import { Component, ViewChild } from '@angular/core';
import { BsModalComponent } from 'ng2-bs3-modal';

@Component({
    selector: 'parent-component',
    template: `
        <bs-modal #myFirstModal>
            ...
        </bs-modal>
        <bs-modal #mySecondModal>
            ...
        </bs-modal>
    `
})
export class ParentComponent {
    @ViewChild('myFirstModal')
    modal1: BsModalComponent;

    @ViewChild('mySecondModal')
    modal2: BsModalComponent;

    ...
}

Modal with a custom size

import { Component, ViewChild } from '@angular/core';
import { BsModalComponent } from 'ng2-bs3-modal';

@Component({
    selector: 'parent-component',
    styles: ['>>> .modal-xl { width: 1100px; }'],
    template: `
        <bs-modal cssClass="modal-xl" #modal>
            ...
        </bs-modal>
    `
})
export class ParentComponent {
    ...
}

Note: Angular2 emulates the shadow dom by prefixing component styles with a unique identifier. Because the modal is attached to the body tag, it doesn't pick up these styles. You will need to add the /deep/ or >>> selector in order for the style to take effect. See Component Styles.

Modal in NgFor

import { Component, ViewChildren } from '@angular/core';
import { BsModalComponent } from 'ng2-bs3-modal';

@Component({
    selector: 'parent-component',
    template: `
        <button type="button" class="btn btn-default" (click)="modal.open()">Open me!</button>
        <div *ngFor="let item in items; trackBy: item.id">
            <bs-modal #modal>
                ...
            </bs-modal>
        </div>
    `
})
export class ParentComponent {
    @ViewChildren(BsModalComponent)
    modals: QueryList<BsModalComponent>; // How to access a collection of modals
    ...
}

Note: If you are updating items asynchronously, make sure you are using trackBy in the ngFor directive so that Angular doesn't teardown and redraw the elements each time the collection is changed. See NgFor Directive for more details.

Modal with validation

<bs-modal #validationModal>
    <form #modalForm="ngForm">
        <bs-modal-header [showDismiss]="true">
            <h4 class="modal-title">I'm a modal!</h4>
        </bs-modal-header>
        <bs-modal-body>
            <div class="form-group">
                <label for="firstName">First Name</label>
                <input type="text" class="form-control" required [(ngModel)]="firstName" name="firstName" id="firstName">
            </div>
            <div class="form-group">
                <label for="lastName">Last Name</label>
                <input type="text" class="form-control" required [(ngModel)]="lastName" name="lastName" id="lastName">
            </div>
        </bs-modal-body>
        <bs-modal-footer>
            <button type="button" class="btn btn-default" data-dismiss="modal" (click)="validationModal.dismiss()">Cancel</button>
            <button type="button" class="btn btn-primary" [disabled]="!modalForm.valid" (click)="validationModal.close()">Save</button>
        </bs-modal-footer>
    </form>
</bs-modal>

Autofocus on a textbox when modal is opened

<bs-modal #modal>
    <bs-modal-header>
        <h4 class="modal-title">I'm a modal!</h4>
    </bs-modal-header>
    <bs-modal-body>
        <div class="form-group">
            <label for="textbox">I'm a textbox!</label>
            <input autofocus type="text" class="form-control" id="textbox">
        </div>        
    </bs-modal-body>
    <bs-modal-footer [showDefaultButtons]="true"></bs-modal-footer>
</bs-modal>

Building

git clone https://github.com/dougludlow/ng2-bs3-modal.git
yarn
yarn build

Running

yarn start

Navigate to http://localhost:4200/ in your browser.

Testing

yarn test:lib

Bugs/Contributions

Report all bugs and feature requests on the issue tracker.

Contributions are welcome! Feel free to open a pull request.