ボクココ

個人開発に関するテックブログ

Rails の render で部分的に動的な HTML を生成する

ども、@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 %>

こうすれば、柔軟なモーダルがどんどんと量産することが可能だ。注意が必要なのは、renderlayout オプションで指定してあげること。こうしないとブロックを利用することができなかった。

あとは 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 については以下の記事でご紹介しているので、もし知らなかった場合は調べておくと良いだろう。

今更ながら jQuery の trigger の魅力について語らせてもらう