#2 RailsとVue.jsでモーダルウィンドウを実装

https://qiita.com/divclass123/items/71465f7a6c313a533eeb
前回の続き。
前回投稿一覧をVue.jsで記述したので、投稿一覧でなにかしらボタンを押したら、
投稿詳細ページが出てくるてきなやつをやってみたい！
動的なページがしっかりと動くのか不安。
https://github.com/euvl/vue-js-modal?ref=kabanoki.net
v-modalで簡単に実装できるからやってみよ。
フロントにvue-jsを使うといろんなライブラリで色々できるからいいね。
https://www.kabanoki.net/3144/
参考記事

# 下準備

```
npm install vue-js-modal --save
```

```html
<div id="app">
  <button v-on:click="show" class="button">show!</button>
  <modal name="hello-world" :draggable="true" :resizable="true">
    <div class="modal-header">
      <h2>Modal title</h2>
    </div>
    <div class="modal-body">
      <p>you're reading this text in a modal!</p>
      <button v-on:click="hide">閉じる</button>
    </div>  
  </modal>
</div>
```

```js
Vue.use(window["vue-js-modal"].default);

var app = new Vue({
  el: '#app',
  methods: {
    show : function() {
      this.$modal.show('hello-world');
    },
    hide : function () {
      this.$modal.hide('hello-world');
    },
  }
})
```

まぁなんとなく雰囲気は掴んだ。

```app.vue

      <modal>
        <drinkShow></drinkShow>
      </modal>

```

```js

import drinkShow from './packs/components/drinks/show.vue'
```

としたら、


app.vue:69 Uncaught Error: Cannot find module './packs/components/like/likeButton.vue'

と、前まで上手くいってた
コンポーネントの読み込みができなくなってる。


show.vueを読み込んだことにより、show.vueのほうでエラーが起きてた。

エラーメッセージが分かりづらい。。。

# モーダルウィンドウは実装できたが、、、

```hello_vue.js

import Vue from 'vue'

import VModal from 'vue-js-modal'
Vue.use(VModal)

```


と記載することでできた。

が、モーダルウィンドウの表示がいかんせんおかしい。

![スクリーンショット 2021-08-26 14.56.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653881/d848b441-30fa-db1d-c826-10aa5c081cb4.png)



この白の部分がモーダルウィンドウ。

んーー。
https://naito-coding0322.hatenablog.com/entry/2018/12/31/002712

まず考えられるのが、
show.vue
で{{drink.name}}

とかやってるが、そのデータの参照先が前までapi::controllerからjbuilderでjson形式でデータを送信したものを参照してたので、{{drink.name}}が効かなくなってる。

ってことで、親コンポーネントから子コンポーネントにデータを渡す。

ただ、それだったらHTML/CSSくらいは、機能しても良い気がする。
そこに関してはvue-js-modalの問題なのか。

```app.vue
  <modal name="display-drink-show" :drink="drink">
```


こんなかんじでコンポーネントを利用した場合に変数を渡して動的なページをモーダルウィンドウ化させることができるらしい。

```app.vue
                  <modal name="display-drink-show" >
                     <drinkShow :drink=drink></drinkShow>
                 </modal>
```


```show.vue
export default {
  props: ['drink']
```


コンナ感じで親から子にデータを受け渡して、たぶんできた。
だがしかし、表示がおかしい。CSSの問題なのであとで直せる。
それよりクリティカルな問題なのが

```app.vue

        <li v-for="drink in drinks" :key="drink.id" class="list" >
         <modal name="display-drink-show" >
            <drinkShow :drink=drink></drinkShow>
           </modal>
        </li>
```

こんな感じで書いてるので、drinksの配列の文だけモーダルウィンドウが繰り返し表示される。
かといって、

```app.vue
        <li v-for="drink in drinks" :key="drink.id" class="list" >

        </li>

         <modal name="display-drink-show" >
            <drinkShow :drink=drink></drinkShow>
           </modal>
```

これだと、drinkが定義されていないので、エラーになる。

原因はshow()が繰り返されてモーダルウィンドウが繰り返し、配列分表示されてしまうので、


```app.vue
        <li v-for="drink in drinks" :key="drink.id" class="list" >
                <modal name="display-drink-{{drink.id}}" >
                  <drinkShow :drink=drink></drinkShow>
                </modal>
                <button v-on:click="show">詳細を表示</button>
        </li>

<script>

    show : function() {
      this.$modal.show('display-drink-{{drink.id}}');
    },
</script>
```

とかやれば(変数展開の文法が正しいかは置いといて)、drink.idはかぶらないので、繰り返し表示されないとおもったが

drinkはv-forの中のローカル変数なので、show()でdrinkを持ってくることができない。。。

```js
    show : function() {
      this.drinks.forEach(drink => {
         this.$modal.show(`display-drink-${drink.id}`);
      });
    },

```

試しにこんな感じで書いてみた。うーーんどうだろう。


```app.vue
        <li v-for="drink in drinks" :key="drink.id" class="list" >
                <modal name="display-drink-7" >
                  <drinkShow :drink=drink></drinkShow>
                </modal>
                <button v-on:click="show">詳細を表示</button>
       </li>

```


```app.vue
    show : function() {
      this.drinks.forEach(drink => {
         this.$modal.show(`display-drink-${drink.id}`);
         console.log(`display-drink-${drink.id}`)
      });
    },
```


こう書いても、配列分繰り返してモーダルウィンドウが表示されてしまった。
んー、、、。


display-drink-11
display-drink-10
display-drink-9
display-drink-8
display-drink-7

かぶらないようなmodalのnameオプションに指定するものができたが、

```app.vue
                <modal name="display-drink-7" >
                  <drinkShow :drink=drink></drinkShow>
                </modal>
                <button v-on:click="show">詳細を表示</button>
```


自分の予想では一回しか表示されないはずだが、、、なぜが配列分モーダルウィンドウが表示されている、。。。

テンプレート部分からスクリプト部分にデータを渡すことができれば、、、、。んーー。どうだろう。

自分の予想では一回しか表示されないはずだが、、、なぜが配列分モーダルウィンドウが表示されている、。。。
ってことは、modal部分が繰り返し処理の中にあると、modalのnameがたとえ一意性があっても、
繰り返し処理される。ってことだから、




```app.vue
        <li v-for="drink in drinks" :key="drink.id" class="list" >

                <button v-on:click="show">詳細を表示</button>
       </li>

                <modal name="display-drink-7" >
                  <drinkShow :drink=drink></drinkShow>
                </modal>

```

modal部分をv-forの外に記述するが、
さっきもいったが、drinkはv-forの中でしか使えない。
にっちもさっちもいかない状態である。。。。

drinksのshowにどうやってデータを渡すかが鍵になってくる。。。。

https://shimablogs.com/vue-modal
俺のやりたいことがあった。

「メソッドを引数として」
といった記述があったので、それをヒントに。

```app.vue
 <button v-on:click="show(drink)">詳細を表示</button>

```

```app.vue

    show : function(drink) {
      this.$modal.show(`display-drink-${drink.id}`);
    },
```

```app.vue
                <modal name="display-drink-7" >
                  <drinkShow :drink=drink></drinkShow>
                </modal>

```


やってることはさっきと変わらないきがするが、どうなんだ。


drink.idが7のやつだけ反応してモーダルが表示されたが、
表示されるときにやはり、たくさん表示されてしまう。
てか、hideメソッド定義してないからじゃね。って思ったので、
一旦やってみるか。


```show.vue

          <button v-on:click="hide()">戻る</button>

  methods: {
    hide : function () {
      this.$modal.hide('display-drink-7');
    }
  }

```

とやったらいけたので、


```app.vue
<modal name="display-drink-${drink.id}" >
   <drinkShow :drink=drink></drinkShow      
 </modal>
```

みたいなことをしたいわけだが、そうは問屋がおろさない。

v-bindとは？属性を動的に設定できる機能
がvue.jsにあるっぽいので、それをやるしかない

```app.vue
                <modal v-bind:name="'display-drink-'+drink.id" >
                  <drinkShow :drink=drink></drinkShow>
                </modal>
```

とやってみた。


したらいけた！！やったぜ！！！！

いやー、ガチで天才すぎるわ。俺。
属性を動的に変えたいと思ってそこからぐぐったらv-bind出てきて、リファレンス見てできちゃった。

![スクリーンショット 2021-08-26 22.52.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653881/0c00eae5-770a-2440-2367-68c21bbcb95b.png)


しかも配列分モーダルが表示される問題があったが、それもなく。戻るボタン押さずにそれ以外の部分押しても
しっかりと投稿一覧に戻ってくれる。
あとは、見た目が。。。
恐らく、最大の問題はmodal部分のheightが足りていない。。。。

#モーダルウィンドウの見た目を整える

モーダルウィンドウを開いたときに検証ツールで見てみたら、
#modals-containerみたいなのあったので、

```app.vue

<style scoped lang="scss">
#modals-container{
  height: 400px;
}
</style>
```

としてみる。

効かない

<style scoped lang="scss">
.vm--modal{
background-color: bisque;
}
</style>

これも効かない

```app.vue
                <modal v-bind:name="'display-drink-'+drink.id"
                 height="1000px" 
                 styles="background-color: bisque">
                  <drinkShow :drink=drink></drinkShow>
                </modal>
```

これでできるっぽい。。。

んーーー。。やったぜ！！？？
でもそうじゃないというのが本音。
まぁ、scriptの方にstyleを定義したやつをまとめるほうが良い気がするがまあいいだろう。。

![スクリーンショット 2021-08-26 23.20.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653881/f172ad16-20f3-75f8-e4db-0b28b5f82f5c.png)

このように表示できた。
一旦成功のように見えるが、実はいいねボタンを押しても機能はしてるが、
モーダルウィンドウを表示していいねを押して、戻ったときに
いいねが押されてない。ことになっている。リロードすると
元の投稿にいいねがつくようになってる。
子コンポーネントの動作と、親コンポーネントの動作が微妙に一致してないので、
次回はそこを修正