0
1

More than 3 years have passed since last update.

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

Posted at

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
<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>
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>


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://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を持ってくることができない。。。

    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

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

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

モーダルウィンドウを開いたときに検証ツールで見てみたら、

modals-containerみたいなのあったので、

app.vue

<style scoped lang="scss">
#modals-container{
  height: 400px;
}
</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

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

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1