Angular4 NgbModalを使ってモーダルウインドウを表示する

NgbModalを使う

最近はionicではなく、Angular4を使った開発を行っています。

Angular4を使って、モーダルウインドウを表示する方法と、モーダルウインドウと元のウインドウのデータ受け渡しについての方法を紹介します

何はともあれAngular Bootstrapを導入

Angular4に特化したBootstrapを使います。
なんとも紛らわしいのですが、Bootstrap4はBootstrap4として存在しています。
Bootstrap4の一部機能を、Angularに特化して使いやすくしたものがBootstrap 4 components, powered by Angularのようです。
(間違ってたらすみません)

インストールはいつものようにnpmで行います。
npm install –save @ng-bootstrap/ng-bootstrap

詳しいインストール方法はGetting Startedを読んでいただければ良いと思います。

1つ注意点として、インストール方法にも書いてありますが

  • Angular (requires Angular version 4 or higher, tested with 4.0.3)
  • Bootstrap CSS (tested with 4.0.0-alpha.6)

が無いと動きません。
これらはnpmでインストールしてもうまくできなかったので、私はCDNで引っ張ってきてしまいました。

index.html

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>sample</title>
  <base href="/">

  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <!-- bootstrap4 -->
  <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
  <link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">

</head>
<body>
  <app-root>Loading...</app-root>
</body>
</html>

10行目付近の処理でBootstrap4.0.0-alpha.6をインストールしています

その他、app.module.tsファイルにも追加していきます。(詳しくは公式ガイドを参照)

NgbModalを導入する

ここから本番です。

Modal用コンポーネントを追加

モーダルウインドウは1つのコンポーネントなので、プロジェクトに1つコンポーネントを追加しておきます。
ターミナルから

ng g component mymodal
と入力して、componentを追加します(mymodalの部分は適時変更して下さい)

Modalを使うためのModule追加

app.module.tsにコンポーネントの情報を追加していきます。

import { NgModule } from '@angular/core';
import { NgbModule} from '@ng-bootstrap/ng-bootstrap';

import { AppComponent } from './app.component';
import { mymodalComponent} from './mymodal/mymodal.component';



@NgModule({
  declarations: [
    mymodalComponent,
  ],
  imports: [
    NgbModule.forRoot(),
  ],
  entryComponents: [mymodalComponent],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

entryComponentsという項目が見慣れないのですが、追加する必要があるようです。これに気づかず少しハマりました。

モーダルウインドウを呼び出す側の処理

NgbModalについて公式のマニュアルはこちらを参照してください

まずモーダルウインドウを呼び出すがわの処理です

import { Component  , Input } from '@angular/core';
import { mymodalComponent} from '../mymodal/mymodal.component';
import { NgbModal } from '@ng-bootstrap/ng-bootstrap';

@Component({
  selector: 'app-base',
  templateUrl: './base.component.html',
  styleUrls: ['./base.component.css']
})
export class baseComponent {

  constructor(private modalService: NgbModal,) {}

  open() {
    const modalRef = this.modalService.open(mymodalComponent);
    modalRef.componentInstance.name = 'モーダルに文字を渡しましょう';
    modalRef.result.then(
      result => {
        console.log(result);
      }
    );
  }
}

templateUrlの方で、適当にボタンでも1つ配置しておきます

<button class="btn btn-lg btn-outline-primary" (click)="open()">Launch demo modal</button>
モーダルウインドウが開く時

ボタンを押すと、openメソッドが実行されます。mymodalComponentを呼び出してモーダルとして表示してくれます。
その際に、モーダルウインドウへパラメータを渡すことができます。サンプルコードでは’モーダルに文字を渡しましょう’ というパラメータを渡しています。

モーダルウインドウが閉じる時

モーダルウインドウの閉じるボタンをクリックして、制御が呼び出し元に戻ってきた際、モーダルウインドウからresultとして値を受け取ることが可能です。
modalRef.result.then以下の処理で受け取ります。受け取った値はサンプルではresultという変数に入ってきます。

モーダルウインドウ本体の作成

mymodal.ts

import { Component ,Input} from '@angular/core';
import { NgbActiveModal} from '@ng-bootstrap/ng-bootstrap';

@Component({
  selector: 'app-mymodal',
  templateUrl: './mymodal.component.html',
  styleUrls: ['./mymodal.component.css']
})
export class mymodalComponent {
  @Input() name;

  constructor(public activeModal: NgbActiveModal) {}
  btn(){
    console.log("おしたな?");
  }
}

@Input() name; で呼び出し元からデータを受け取ります。サンプルでは
モーダルに文字を渡しましょう
が入ってきます。

モーダルウインドウのtemplateURL側

<div class="modal-header">
  <h4 class="modal-title">Hi there!</h4>
  <button type="button" class="close" aria-label="Close" (click)="activeModal.dismiss('Cross click')">
    <span aria-hidden="true">&times;</span>
  </button>
</div>
<div class="modal-body">
  <p>Hello, {{name}}!</p>
</div>
<button (click)="btn()">hoge</button>
<div class="modal-footer">
  <button type="button" class="btn btn-secondary" (click)="activeModal.close('Close click')">Close</button>
</div>

呼び出し元から受け取った文字を画面に表示しています。
ついでにボタンを2つ配置しています。1つはconsole.logを、1つはモーダルウインドウを閉じます。
activeModal.close()の引数に渡したあたいが、呼び出し元に渡す値になります。