GASでWebアプリ｢映画鑑賞記録｣を作る⑥ ／ Vue.jsでダイアログボックスを表示する（後編）

# 今回やること
　前回の続き。
　今まで、本アプリの機能をBootstrapとjQueryで実現していましたが、Vue.jsに変更します。

　今回は「ダイアログボックスの変更」に対応します。

- Vue.jsの導入
- サーバから取得したデータの処理を変更
- **ダイアログボックスの変更**

　今回追加するファイルは、**modalScript.html** と **modalStyle.html** です。

# ダイアログボックスの変更
#### Vuejs.html
　次のコードを追加します。
　ダイアログボックスは、子コンポーネントとして動作します。
　詳しくは、他のサイトや書籍を参照してください。 

1. `props:`がダイアログボックスで使用するデータとなります。   
　**・**`subject` ：実行ボタンに表示される文字列。 ex. `　追　加　` or `　更　新　`   
　**・**`cond`　　：鑑賞記録の各項目。「ID」「鑑賞日」「タイトル」「映画館」「初見」等
1. `methods:`がダイアログボックスで使用するメソッドとなります。   
　**・**`addData`：ダイアログボックスに入力されたデータを鑑賞記録に更新（追加）する処理。   
`this.$emit('add-data', this.cond)`が、**Index.html** の`v-on:add-data="doAddData"`で関連付けられ、`new Vue()`（親コンポーネント）の`doAddData`が実行されます。その関数の引数として前項の`cond`が渡されます。

　◆参考書籍のサイト [「基礎から学ぶ Vue.js」mio著 C&R研究所](https://www.c-r.com/book/detail/1230)

```html
<script>  
Vue.component("modal", {
  template: "#modal-template",
  props: {
    message: String,
    subject: String,
    cond: {
      id: Number,
      viewingDate: String,
      movieName: String,
      theaterName: String,
      firstLook: Number,
      viewingType: Number
    }
  },
  methods: {
    addData: function() {
      this.$emit('add-data', this.cond);
    }
  }
});
```

`new Vue({…})`の内容を次の様に修正します。

1. `data:`に次の変数を追加。   
**・**`processingType`：処理種別をダイアログボックスのヘッダーに表示します。   
**・**`subject`　　　　：実行ボタンに表示される文字列。   
**・**`showModal`　　　：ダイアログボックスの表示・非表示を制御するフラグ。   
　　　　　　　　　　　`true`で表示されます。   
**・**`cond`　　　　　 ：鑑賞記録の各項目。   
1. `methods:`に各処理を追加します。   
**・**`doAddData`　　　　 ： **javascript.html** の`addData(cond)`を実行します。   
**・**`doHideModal`　　　 ：ダイアログボックスを非表示にします。   
**・**`doShowModal`　　　 ：ダイアログボックスを【追加処理】で表示にします。      
**・**`doShowModalUpdate`：ダイアログボックスを【更新処理】で表示にします。   
**・**`convertDate`　　　 ：`filters:`の`convDate`と同様の処理を行います。  

```javascript
var app = new Vue({
  el: '#app',
  data: {
    processingType: '記録追加',
    message: 'テスト',
    subject: '　追　加　',
    showModal: false,
    records: [],
    cond: {
      id: 0,
      viewingDate: '',
      movieName: '',
      theaterName: '',
      firstLook: 1,
      viewingType: 1
    }
  },
  mounted: function() {
    searchResults();
  },
  filters: {
    convDate: function(date) {
      let day = moment(date);
      let res = (day.month() + 1) + '/' + day.date();
      return res;
    }
  },
  methods: {
    doAddData: function(cond) {
      this.showModal = false;
      addData(cond);
    },
    doHideModal: function() {
      this.showModal = false;
    },
    doShowModal: function() {
      this.processingType = '記録追加';
      this.subject = '　追　加　';
      this.cond.id = 0;
      let today = moment(new Date());
      this.cond.viewingDate = (today.month() + 1) + '/' + today.date();
      this.cond.movieName = '';
      this.cond.theaterName = '';
      this.cond.firstLook = 1;
      this.cond.viewingType = 1;
      this.showModal = true;
    },
    doShowModalUpdate: function(index) {
      this.processingType = '記録更新';
      this.subject = '　更　新　';
      this.cond.id = this.records[index][0];
      this.cond.viewingDate = this.convertDate(this.records[index][1]);
      this.cond.movieName = this.records[index][2];
      this.cond.firstLook = this.records[index][3];
      this.cond.viewingType = this.records[index][4];
      this.cond.theaterName = this.records[index][5];
      this.showModal = true;
    },
    convertDate: function(date) {
      let day = moment(date);
      let res = (day.month() + 1) + '/' + day.date();
      return res;
    }
  }
})
```


#### modalScript.html
　ダイアログボックス（モダール）のテンプレートです。

1. `{{ message }}`は、**Vuejs.html** の`Vue.component("modal")`の`message`を参照します。
1. `v-if="cond.id !== 0"`で、当該`<div>`の内容の表示を制御します。式が`真`の場合に表示されます。   
`cond.id`は、`Vue.component("modal")`（以下同様）の`id`を参照しています。   
【追加処理】の場合、`id`に`0`がセットされる為に「ID」項目は表示されません。
1. `<input type="text" … v-model="cond.id"`で、当該`<input>`と`id`が関連付けられます。   
`id`の値が`<input>`項目に表示され、画面の同項目に入力された値が`id`へ自動的に反映されます。   
（他の入力項目も同様です）
1. `<button type="button" … @click="addData">`は、当該`<button>`のクリック時に**Vuejs.html** の`Vue.component("modal")`の`addData`が実行されます。
1. `<button type="button" … @click="$emit('close-modal')">`は、**Index.html** の`v-on:close-modal="doHideModal"`で関連付けられ、**Vuejs.html** の`new Vue()`（親コンポーネント）の`doHideModal`が実行されます。

　**◆参考サイト** [「Vue.js 公式サイト」／モーダルコンポーネント の例](https://jp.vuejs.org/v2/examples/modal.html)

```html
<script type="text/x-template" id="modal-template">
  <transition name="modal">
    <div class="modal-mask">
      <div class="modal-wrapper">
        <div class="modal-container">

          <div class="modal-header">
            <slot name="header">
              default header
            </slot>
          </div>

          <div class="modal-body">
            <slot name="body">
              default body {{ message }}
            </slot>
            <form>
              <div class="form-group" id="data-id-group" v-if="cond.id !== 0">
              <div class="input-group">
                <label for="data-id" class="col-form-label">ID：</label>
                <input type="text" class="form-control" id="data-id" v-model="cond.id" readonly>
              </div>
              </div>
              <div class="form-group">
              <div class="input-group">
                <label for="viewing-date" class="col-form-label">鑑賞日：</label>
                <input type="text" class="form-control" id="viewing-date" v-model="cond.viewingDate">
              </div>
              </div>
              <div class="form-group">
                <label for="movie-name" class="col-form-label">タイトル：</label>
                <input type="text" class="form-control" id="movie-name" v-model="cond.movieName">
              </div>
              <div class="form-group">
                <label for="theater-name" class="col-form-label">映画館：</label>
                <input type="text" class="form-control" id="theater-name" v-model="cond.theaterName">
              </div>
              <div class="form-group">
              <div class="input-group">
                <label for="first-look" class="col-form-label">初見：</label>
                <input type="text" class="form-control" id="first-look" v-model="cond.firstLook">
              </div>
              </div>
              <div class="form-group">
              <div class="input-group">
                <label for="viewing-type" class="col-form-label">鑑賞種別：</label>
                <input type="text" class="form-control" id="viewing-type" v-model="cond.viewingType">
              </div>
              </div>
            </form>
          </div>

          <div class="modal-footer">
            <slot name="footer">
              default footer
              <button type="button" class="modal-default-button btn btn-primary" @click="addData">{{ subject }}</button>
              <button type="button" class="modal-default-button btn btn-secondary" @click="$emit('close-modal')">閉じる</button>
            </slot>
          </div>
        </div>
      </div>
    </div>
  </transition>
</script>
```

#### modalStyle.html
　ダイアログボックス（モダール）のスタイルシートです。
　ほぼ、参考サイトの内容をそのまま使っています。
　**◆参考サイト** [「Vue.js 公式サイト」／モーダルコンポーネント の例](https://jp.vuejs.org/v2/examples/modal.html)

```html
<style>
.modal-mask {
  position: fixed;
  z-index: 9998;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: table;
  transition: opacity 0.3s ease;
}

.modal-wrapper {
  display: table-cell;
  vertical-align: middle;
}

.modal-container {
  width: 550px;
  margin: 0px auto;
  padding: 20px 30px;
  background-color: #fff;
  border-radius: 2px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
  transition: all 0.3s ease;
  font-family: Helvetica, Arial, sans-serif;
}

.modal-header h3 {
  margin-top: 0;
  color: #42b983;
}

.modal-body {
  margin: 0 0 20px 0;
  padding: 10px;
}

.modal-footer {
  display: block;
}

.modal-default-button {
  float: right;
}

/*
 * The following styles are auto-applied to elements with
 * transition="modal" when their visibility is toggled
 * by Vue.js.
 *
 * You can easily play with the modal transition by editing
 * these styles.
 */

.modal-enter {
  opacity: 0;
}

.modal-leave-active {
  opacity: 0;
}

.modal-enter .modal-container,
.modal-leave-active .modal-container {
  -webkit-transform: scale(1.1);
  transform: scale(1.1);
}
</style>
```

#### Index.html

　次の修正を行います。

　`<button>`を変更します。
　`<button>`をクリックすると、**Vuejs.html** の`new Vue()`の`doShowModal`が実行されます。

```html
    <div style="text-align: center;">
      <button type="button" class="btn btn-primary" id="show-modal" @click="doShowModal">記録追加</button>
    </div>
```
```:以前の記述
    <div style="text-align: center;">
      <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-processing-type="記録追加">記録追加</button>
    </div>
```

　`<modal>`を追加します。
　ここにダイアログボックス（子コンポーネント）と親コンポーネントとの関連付けを記述します。

- `showModal`は、**Vuejs.html** の`new Vue()`の`showModal`を参照します。
- `v-on:△△△△="※※※※"`は、関数を関連付けます。   
子コンポーネントから`this.$emit('△△△△')`を実行する事により、**Vuejs.html** の`new Vue()`（親コンポーネント）の`※※※※`（メソッド）を実行する事ができます。
- `v--bind:◇◇◇◇="▽▽▽▽"`は、変数を関連付けます。    
**Vuejs.html** の`new Vue()`（親コンポーネント）の`▽▽▽▽`に値をセットする事により、`Vue.component("modal")`（子コンポーネント）の`◇◇◇◇`でも同じ値を参照できます。
- `<h3 slot="header">`は、ダイアログボックス（子コンポーネント）のヘッダー部（**modalScript.html** の`<slot name="header">`）に置き換えられます。   
`{{ processingType }}`は、**Vuejs.html** の`new Vue()`の`processingType`を参照します。

```html
    <modal v-if="showModal" v-on:close-modal="doHideModal" v-on:add-data="doAddData" v-bind:message="message" v-bind:subject="subject" v-bind:cond="cond">
      <h3 slot="header">custom header {{ processingType }}</h3>
    </modal>
```
# 結果
　〔記録追加〕ボタンのクリックで、記録追加用のダイアログボックスが、
![ダイアログボックス_追加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510221/301fdf6c-c54b-b4c1-da70-265bbde002bc.png)
　一覧表の行をクリックする事で、記録更新用のダイアログボックスが表示される様になりました。
![ダイアログボックス_更新.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510221/24d834c0-f7ef-65ef-21e0-028e912c1715.png)
　※ダイアログボックスの表示には、不要な表示も残っています。:sweat: :sweat_drops:  

**◆前の記事** [GASでWebアプリ｢映画鑑賞記録｣を作る⑤](https://qiita.com/pump33/items/b5f42ddd139e887b36df)
**◆次の記事** [GASでWebアプリ｢映画鑑賞記録｣を作る⑦](https://qiita.com/pump33/items/0b24ecaf3d2de73ec699)

**◆索引** [GASでWebアプリ｢映画鑑賞記録｣を作る《索引》](https://qiita.com/pump33/items/8ded0e6fd3c336e705f4)