ngx-bootstrapのmodalとng-fullcalendarを併用した時におきた問題について

こんにちは、[BBG](https://bbank.jp/)の[清水](https://twitter.com/shimikyonkyon)です。
ngx-bootstrapのmodalとng-fullcalendarを併用した時におきた問題について話します。

### やりたいこと

- [fullcalendar](https://fullcalendar.io/)で実装していたカレンダーをAngularアプリケーション内に表示したい
- カレンダーは、`ngx-bootstrap`のmodal上に表示したい

**環境**
- Angular: 6.0.0
- jquery: ^3.2.1
- ngx-bootstrap: ^3.1.3
- fullcalendar: 3.6.1
- ng-fullcalendar: ^1.7.1


Angularで使えそうなcalendarライブラリを探していたら次の２つが見つかりました。
- [ng-fullcalendar](https://github.com/ng-fullcalendar/ng-fullcalendar)
- [angular-calendar](https://github.com/mattlewis92/angular-calendar) 

[angular-calendar の方が人気なのかー](https://www.npmtrends.com/angular-calendar-vs-ng-fullcalendar)と思いつつも
今回は、fullcalendarで作られたカレンダーのリプレースだったので`ng-fullcalendar`を起用しました。


### ng-fullcalendarを使ってみる
ソースコードはこんな感じです。（installなどはdocsにあるので省略します。）

```html:html
<div bsModal #modal="bs-modal" class="modal" role="dialog">
  <div class="modal-dialog">
    <div class="fullcalendar-content" *ngIf="calendarOptions">
    <div class="fullcalendar-header">
      ...
    </div>
    <ng-fullcalendar [options]="calendarOptions" ... >
    </ng-fullcalendar>
  </div>
</div>
```
```typescript:ts
import { Component, OnInit } from '@angular/core';
import { CalendarComponent } from 'ng-fullcalendar';
import { Options } from 'fullcalendar';

@Component({ ... })
export class CalendarComponent implements OnInit {
  calendarOptions: Options;

  constructor(){}

  ngOnInit() {
    this.calendarOptions = {
      allDayText: '終日',
      contentHeight: 600,
      editable: true,
      eventLimit: false,
      events: [],
      firstDay: 0,
      header: false,
      locale: 'ja',
      slotLabelFormat: 'H:mm',
      selectable: true,
      timeFormat: 'H:mm',
      views: {
        month: {
          columnFormat: 'ddd',
          titleFormat: 'YYYY年MM月',
        },
        week: {
          columnFormat: 'MM/DD（ddd）',
          titleFormat: 'YYYY年MM月DD日',
        },
        day: {
          columnFormat: 'MM/DD（ddd）',
          titleFormat: 'YYYY年MM月DD日（ddd）',
        },
      },
    };
  }
}
```
カレンダーのヘッダはカスタムしたかったので、デフォルト表示をfalseにしました。

### 問題がおきた。。
<img width="1438" alt="スクリーンショット 2019-03-04 9.53.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/238961/e1dfd939-a785-4c5d-e92d-9f098b288aa6.png">
モーダルを開いてみると日付エリアが表示されない問題が、、
モーダル以外で表示しようとすると期待した動作をしました。

これは、bootstraptとfullcalendarを併用した時に発生するfullcalendarのバグのようです。
bootstrapの他module内にfullcalendarを表示しようたら同じような現象がおきた、という人もいました。

### 解決
bootstrapのmoduleを表示した後に、カレンダーの表示をしてあげれば解決しそうだったので[ModalModule](https://valor-software.com/ngx-bootstrap/#/modals#api-reference)の`onShown`を使用して次のような実装に修正しました。

```typescript:ts
import { Component, OnInit, ViewChild } from '@angular/core';
import { CalendarComponent } from 'ng-fullcalendar';
import { Options } from 'fullcalendar';
import { ModalDirective } from 'ngx-bootstrap/modal';

@Component({ ... })
export class CalendarComponent implements OnInit {
  calendarOptions: Options;
  @ViewChild('modal') modal: ModalDirective;

  constructor(){}

  ngOnInit() {
    this.modal.onShown.subscribe(() => {
      this.calendarOptions = { ... };
    });
  }
}
```

表示されました、めでたし！
<img width="1436" alt="スクリーンショット 2019-03-04 9.52.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/238961/3792a752-8f51-7b2d-dc5a-8249521b4ef8.png">

### 終わりに
ng-fullcalendarでfullcalendarのカレンダーが簡単に利用できました。
ただ、bootstrapと併用するとバグがあるのと、まだAnugular7以降には対応してなさそうなので今後Angularのバージョンに追随していくのかが気になっています。
`angular-calendar` も今度触ってみようと思います！