ども、@kimihom です。
Rails で CSS フレームワークとかを使っていると、例えばモーダルウィンドウを出すためにヘッダやフッタで共通の HTML を使うことになるだろう。これらは大抵の場合、共通の UI となる。それでも当然、モーダル内の body の部分はそれぞれ別々の HTML を書けるようにしたい。そんな場合にどうしたらいいのかをご紹介しよう。
共通部分を 別 html で切り出そう
Rails といえば DRY(Don't Repeat Yourself)だ。同じコードをコピペするようなことはしてはならない。それは HTML でも同様のことだ。同じコードが出てくるようなら、まずは app/views/home/_modal.html.erb
のように切り出そう。今回のHTML断片は Bulma を使ったモーダルの例。
modal.html.erb
<div class="modal <%= class_name %>"> <div class="modal-background"></div> <div class="modal-card"> <header class="modal-card-head"> <p class="modal-card-title"><%= title %></p> <button class="delete"></button> </header> <section class="modal-card-body"> <%= yield %> </section> <footer class="modal-card-foot"> <a class="button is-primary action"><%= action_name %></a> </footer> </div> </div>
そんで、呼び出し元の HTML を <%= render %>
の引数とブロックで値とHTMLを引数として渡すことができる。
<%= render layout: "modal", locals: { class_name: "hello", title: "Hello World", action_name: "Agree" } do %> <p> Are you agree? </p> <% end %>
こうすれば、柔軟なモーダルがどんどんと量産することが可能だ。注意が必要なのは、render
の layout
オプションで指定してあげること。こうしないとブロックを利用することができなかった。
あとは JavaScript 側で Modal を表示するような処理を書けばOKだ。
モーダル内容を JavaScript で動的に書き換える
まぁたいていの場合ってのはこのモーダル内容をさらに JavaScript で動的に表示したいということがあるだろう。 Rails の View 内でそれが完結できればいいが、 JavaScript 側の値で動的に表示したい場合は、modal 表示前のイベントをキャッチして、HTMLを書き換える必要がある。
$(document).on("click", "#console-ctrl .open-modal", function() { var target = $(this).attr("data-modal"); var attr = $(this).attr("data-modal-attribute"); $target = $("#console-ctrl .modal." + target); $target.trigger("modal:before-open", attr); $target.addClass("is-active"); }); $(document).on("click", "#console-ctrl .modal .delete", function() { $("#console-ctrl .modal").removeClass("is-active"); }); $(document).on("modal:before-open", ".modal.hello", function(attr) { console.log("hello modal before open"); });
こんな感じにしてあげれば、 モーダルを表示する HTML 側で共通で書くことができる。
<i class="fa fa-plus-circle add-person open-modal" data-modal="hello"></i>
このフォントをクリックすると、さっきの hello
なモーダルが表示されるようになる。そしてその描画前に、modal:before-open
のイベントが発火するようになる。
終わりに
特にCSSフレームワークとかを使っていると、共通な部分ってのはよく出てくる。これらをうまく共通化して、テンプレートとして保存するようにすればより美しく汎用性の高いコードを書くことが可能だ。
今回は jQuery の trigger を利用した。この trigger については以下の記事でご紹介しているので、もし知らなかった場合は調べておくと良いだろう。