8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Elixir] Phoenix 1.8でcore_componentsから消えたモーダルをdaisyUI版に転生させる

Last updated at Posted at 2025-12-18

この記事は Elixir Advent Calendar 2025 シリーズ4の19日目です。昨日は @mnishiguchi さんでした!


先日の記事で、Phoenix 1.8から core_components.ex にはモーダルが含まれないと紹介しました。

imagepix では、各リソースを削除する際に確認モーダルを出すようにしています。別の記事で onclick属性を使う方法 が紹介されていますが、Phoenix 1.7のモーダルと同じような使い勝手にしたかったので、ちょっとだけ工夫しました。

モーダルの使用例

先に使用例を紹介します。モーダル外のボタンを押すとモーダルが開き、モーダル内のCancelボタンを押すとモーダルが閉じるというものです。Phoenix 1.7でも同じようなコードになります。

<.button variant="danger" phx-click={show_modal("remove-member-modal")}>
  Remove this member
</.button>

<.modal id="remove-member-modal" title="Remove this member">
  Are you sure to remove this member from Smart Algorithm Co., Ltd.? This action cannot be undone.
  <:actions>
    <.button variant="danger" phx-click="delete">Remove this member</.button>
  </:actions>
</.modal>

モーダル外の「Remove this member」ボタンを押すと、以下のようにモーダルが表示されます。「Cancel」ボタン(modalコンポーネント内で定義)を押すと、モーダルが閉じます。

image.png

モーダル本体の定義

daisyUIのモーダル には実装方法が3つありますが、推奨されている <dialog> を使った実装方法を採用します。

core_components.ex
def modal(assigns) do
  ~H"""
  <dialog id={@id} class="modal" phx-hook=".Modal">
    <div class="modal-box">
      <h3 class="text-lg font-bold">{@title}</h3>
      <div class="py-4">{render_slot(@inner_block)}</div>
      <div class="modal-action">
        <.button phx-click={hide_modal(@id)}>Cancel</.button>
        {render_slot(@actions)}
      </div>
    </div>
  </dialog>
  <script :type={ColocatedHook} name=".Modal">
    export default {
      mounted() {
        this.el.addEventListener("show", () => {
          this.el.showModal()
        })
        this.el.addEventListener("hide", () => {
          this.el.close()
        })
      }
    };
  </script>
  """
end

モーダルの操作にはJavaScriptを使う必要があります。今回は開くか閉じるかしか使わないので、Colocated Hooks で実装します。show イベントを受け取ったら showModal() を実行し、hide イベントを受け取ったら close() を実行するだけで、簡単ですね。

モーダルの操作

Phoenix 1.7ではモーダルを操作する show_modal/2hide_modal/2 があったので、同じインターフェイスで実装します。

core_components.ex
def show_modal(js \\ %JS{}, id) do
  JS.dispatch(js, "show", to: "##{id}")
end

def hide_modal(js \\ %JS{}, id) do
  JS.dispatch(js, "hide", to: "##{id}")
end

Phoenix 1.7のモーダルは単なる <div> 要素だったので JS.show/2JS.hide/2 で操作していましたが、daisyUIのモーダルを操作するにはJavaScriptを使う必要があるため、今回はColocated Hooksを使って操作するようにしています。JS.dispatch/2show イベントや hide イベントを指定したIDの要素に送るように実装することで、以下のような使い方でモーダルを操作できるようになります。

ボタンを押すとshowイベントが送られモーダルが開く
<.button variant="danger" phx-click={show_modal("remove-member-modal")}>
  Remove this member
</.button>
ボタンを押すとhideイベントが送られモーダルが閉じる
<.button phx-click={hide_modal("remove-member-modal")}>Cancel</.button>

最後に

これまでColocated Hooksを使ったことはありませんでしたが、ちょうどいい事例が見つかりました。

最近のフロントエンドフレームワークではテンプレートとロジックを同じファイル内に記述するものが多いですが、Phoenixもそれに近づいていってる印象です。フロントエンドフレームワークでバックエンドの処理も実装することが多くなってきていますし、PhoenixやLiveViewの採用がもっと広がっていくと良いですね :sparkles:


明日の Elixir Advent Calendar 2025 シリーズ4の20日目は @mnishiguchi さんです!
お楽しみに :rocket:

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?