先月末にバージョン 0.1 が公開され、Hex からインストールできるようになりました。
これを機に Phoenix.LiveView に挑戦です。
この記事では、app 作成から LiveView で表示を動かすまでの作業を、ただ淡々と書いてゆきます。
準備
適当な Phoenix app を用意します。
以降の説明のために、ここでは DB (Ecto) を利用しない app を新規に作成します。
$ mix phx.new my_app --no-ecto $ cd my_app
パッケージを追加する
mix.exs を編集して phoenix_live_view
を追加します。
--- a/mix.exs +++ b/mix.exs @@ -38,7 +38,8 @@ defmodule MyApp.MixProject do {:phoenix_live_reload, "~> 1.2", only: :dev}, {:gettext, "~> 0.11"}, {:jason, "~> 1.0"}, - {:plug_cowboy, "~> 2.0"} + {:plug_cowboy, "~> 2.0"}, + {:phoenix_live_view, "~> 0.1"} ] end end
$ mix deps.get
assets/package.json
に JavaScript で利用するパッケージの依存情報を追加します。
--- a/assets/package.json +++ b/assets/package.json @@ -7,7 +7,8 @@ }, "dependencies": { "phoenix": "file:../deps/phoenix", - "phoenix_html": "file:../deps/phoenix_html" + "phoenix_html": "file:../deps/phoenix_html", + "phoenix_live_view": "file:../deps/phoenix_live_view" },
$ npm install --prefix assets
Endpoint を編集する
lib/my_app_web/endpoint.ex
を編集し、 LiveView で使うソケットを設定します。
--- a/lib/my_app_web/endpoint.ex +++ b/lib/my_app_web/endpoint.ex @@ -5,6 +5,8 @@ defmodule MyAppWeb.Endpoint do websocket: true, longpoll: false + socket "/live", Phoenix.LiveView.Socket
ソケットのクライアントを設定する
assets/js/app.js
を編集し、ソケットに接続するためのクライアントのコードを追加します。
--- a/assets/js/app.js +++ b/assets/js/app.js @@ -15,3 +15,8 @@ import "phoenix_html" // // Local files can be imported directly using relative paths, for example: // import socket from "./socket" + +import LiveSocket from "phoenix_live_view" + +let liveSocket = new LiveSocket("/live") +liveSocket.connect()
salt を設定する
config/config.exs
の endpoint の設定の項目に :live_view
を追加し、キーワードリストに :signing_salt
を設定します。
--- a/config/config.exs +++ b/config/config.exs @@ -10,11 +10,12 @@ use Mix.Config # Configures the endpoint config :my_app, MyAppWeb.Endpoint, url: [host: "localhost"], secret_key_base: "QshB2lH5dWIXtZFX9mewWHeY/Lt/EpyQv/ErFXjXMfDmstWH3eQ9dVqM2rfdGLBX", render_errors: [view: MyAppWeb.ErrorView, accepts: ~w(html json)], - pubsub: [name: MyApp.PubSub, adapter: Phoenix.PubSub.PG2] + pubsub: [name: MyApp.PubSub, adapter: Phoenix.PubSub.PG2], + live_view: [signing_salt: "some-secure-salt"]
モジュールを追加する
ディレクトリ lib/my_app_web/live
を作成し LiveView のモジュール MyAppWeb.SampleLIve
を定義したファイル lib/my_app_web/live/sample_live.ex
を作成します。
defmodule MyAppWeb.SampleLive do use Phoenix.LiveView def render(assigns) do ~L""" Hello Phoenix.LiveView world! """ end def mount(_session, socket) do {:ok, socket} end end
router を設定する
lib/my_app_web/router.ex
を編集し、MyAppWeb.SampleLIve
を利用する routing を追加します。
--- a/lib/my_app_web/router.ex +++ b/lib/my_app_web/router.ex @@ -1,26 +1,28 @@ defmodule MyAppWeb.Router do use MyAppWeb, :router + import Phoenix.LiveView.Router pipeline :browser do plug :accepts, ["html"] plug :fetch_session plug :fetch_flash plug :protect_from_forgery plug :put_secure_browser_headers end pipeline :api do plug :accepts, ["json"] end scope "/", MyAppWeb do pipe_through :browser get "/", PageController, :index + live "/sample", SampleLive end
最初の表示
app を起動し、http://localhost:4000/sample
にアクセスします。
$ iex -S mix phx.server
MyAppWeb.SampleLIve
の render/1
に記述した内容がレンダリングされ表示されました。
view と template を追加する
LiveView のモジュール内に sigil ( ~L
) で記述する代わりに view と template で表示するように変更します。
新規に view のファイル lib/my_app_web/views/sample_view.ex
を作成してモジュール MyAppWeb.SampleView
を定義します。
defmodule MyAppWeb.SampleView do use MyAppWeb, :view end
同じく新規に template のファイル lib/my_app_web/templates/sample/show.html.leex
を作成してテンプレートを記述します。LiveView のテンプレートは拡張子が .leex
になります。
<h1><%= @message %></h1>
モジュール MyAppWeb.SampleLive
の render/1
の記述を上で追加した view と template を使うように変更します。
def render(assigns) do Phoenix.View.render(MyAppWeb.SampleView, "show.html", message: "Hello Phoenix.LiveView world!") end
:message
で与えた文字列が、テンプレートに記述したタグ <h1>
で装飾されて表示されることが確認できます。
click をハンドリングする
lib/my_app_web/templates/sample/show.html.leex
を次のように変更します。
<h1><%= @message %></h1> <button phx-click="add" phx-value-char="A">A</button> <button phx-click="add" phx-value-char="B">B</button> <button phx-click="add" phx-value-char="C">C</button> <button phx-click="clear">clear</button> <div> > <%= @str %> </div>
タグ button
に指定した phx-click
が click のイベントとして LiveView のモジュールで定義するハンドラ handle_event/3
に渡されます。
また phx-value-*
で指定した値がイベントの値として一緒にハンドラに渡されます。
MyAppWeb.SampleLive
に handle_event/3
を実際に追加します。
defmodule MyAppWeb.SampleLive do use Phoenix.LiveView def render(assigns) do Phoenix.View.render(MyAppWeb.SampleView, "show.html", message: "Hello Phoenix.LiveView world!", str: assigns.str) end def mount(_session, socket) do {:ok, assign(socket, :str, "")} end def handle_event("add", %{"char" => char}, socket) do str = socket.assigns.str new_socket = socket |> assign(:str, str <> char) {:noreply, new_socket} end def handle_event("clear", _, socket) do {:noreply, assign(socket, :str, "")} end end
A
, B
, C
の各ボタンで文字列に文字が追加され、clear
ボタンで文字列がクリアされます。
フォームのイベントをハンドリングする
lib/my_app_web/templates/sample/show.html.leex
にフォームを追加します。また入力結果を表示するための要素も追加します。
フォームで変更が発生すると phx-change
で指定されたイベントが発生します。また submit した場合は phx-submit
で指定したイベントが発生します。
<h1><%= @message %></h1> <button phx-click="add" phx-value-char="A">A</button> <button phx-click="add" phx-value-char="B">B</button> <button phx-click="add" phx-value-char="C">C</button> <button phx-click="clear">clear</button> <div> > <%= @str %> </div> <hr /> <form phx-change="update" phx-submit="submit"> <input type="text" name="text"> </form> <div> > <%= @text %> </div> <ul> <%= Enum.map(@texts, fn text -> %> <li><%= text %></li> <% end) %> </ul>
LiveView のモジュールにハンドラを追加します。
イベント update
が発生すると input
タグの name
で指定した値をパラメータとしてハンドラが呼び出されます。
ここでは input
タグに文字列の入力があると、それを反転した文字列を表示し、submit されるとその反転された文字列をリストに追加する処理を追加しました。
defmodule MyAppWeb.SampleLive do use Phoenix.LiveView def render(assigns) do params = [ message: "Hello Phoenix.LiveView world!", str: assigns.str, text: assigns.text, texts: assigns.texts ] Phoenix.View.render(MyAppWeb.SampleView, "show.html", params) end def mount(_session, socket) do new_socket = socket |> assign(:str, "") |> assign(:text, "") |> assign(:texts, []) {:ok, new_socket} end def handle_event("add", %{"char" => char}, socket) do str = socket.assigns.str new_socket = socket |> assign(:str, str <> char) {:noreply, new_socket} end def handle_event("clear", _, socket) do {:noreply, assign(socket, :str, "")} end def handle_event("update", %{"text" => text}, socket) do new_socket = socket |> assign(:text, String.reverse(text)) {:noreply, new_socket} end def handle_event("submit", _, socket) do new_socket = socket |> assign(:text, "") |> assign(:texts, [socket.assigns.text | socket.assigns.texts]) {:noreply, new_socket} end end
実行結果です。
ここでは form
タグを直接記述したので phx-change
, phx-submit
という形で記述しましたが、Phoenix.HTML.Form.form_for/3
を利用する場合はドキュメントにあるように、オプションに :phx_change
, :phx_submit
とハイフンをアンダスコアに置き換えたキーで指定します。
いつか読むはずっと読まない:博物館の後ろ側、あるいは本当の顔
研究者から見た大英自然史博物館の様子を語った一冊。
博物館には一般の来場者の目の届かないところに膨大な資料が保存され様々な人々の営みがあることに目を向けさせられます。

- 作者: リチャード・フォーティ,渡辺政隆,野中香方子
- 出版社/メーカー: NHK出版
- 発売日: 2011/04/22
- メディア: 単行本
- 購入: 5人 クリック: 33回
- この商品を含むブログ (14件) を見る

- 作者: 早良朋
- 出版社/メーカー: 小学館
- 発売日: 2019/08/09
- メディア: コミック
- この商品を含むブログを見る