LoginSignup
6
1

More than 3 years have passed since last update.

PhoenixLiveViewの0.2.0-devベースでカウンタを作ってみた

Posted at

JavaScriptを記述しないでSPA(シングルページアプリケーション)のような操作ができるPhoenixのライブラリ「 Phoenix LiveView 」ですが、GitHubページのCHANGELOGを見ていると2019年8月末あたりからバージョニングされていたのに気づきました。

せっかくバージョンが0.1系から0.2系に変わっていたのに気づいたので、興味本位で少し触ってみました。

はじめに

Phoenix LiveViewを利用して、ボタンクリックによって数値numの増減とともに、その数値をベースに計算結果(FizzBuzzの判定とフィボナッチ数の算出)を返す画面を作成しました。

操作イメージは、以下のGif画像を参照ください。
LiveView_0.2.0.dev_2.gif

外側のボタンでは値を増減した後で計算結果も算出します。
一方、内側のボタンは計算をしないでベースになる値だけを増減させます。
真ん中のボタンは全ての数値を0に戻します。

ベースになる実装内容については、こちらの記事を参考にしています。
https://qiita.com/kikuyuta/items/c5b0788ad5d09c210c0a

補足事項

Phoenix LiveViewはバージョンアップも頻繁に行われていますので、もしかしたら今回の内容で動作できなくなる場合もあります。
修正箇所に気づいたら、できる限り記事の更新は行う予定です。

環境構築について

Phoenixのプロジェクト名については「 hiyoko 」としています。
そのため、パス名やモジュール名は「 hiyoko_web 」や「 HiyokoWeb 」のような名称になっています。
もし、ご自身のプロジェクトで実施させる際には、プロジェクト名に由来する箇所は読み替えてください。

環境構築についても、先ほど挙げたこちらの記事を参考にしています。

ただし、0.2.0-devへのバージョンアップに伴い、「assets/js/app.js」に対して 後方互換のない変更 が発生していました。以前の内容と比べて、以下の点で変更が必要です。

  • import {Socket} from "phoenix"」 の追記
  • LiveSocket("/live", Socket)」のように第二引数へ「Socket」を追加
assets/js/app.js
import {Socket} from "phoenix"
import LiveSocket from "phoenix_live_view"

let liveSocket = new LiveSocket("/live", Socket)
liveSocket.connect()

コードの記述

Elixir側で記述したコードは、以下の内容です。
ボタンクリック(phx-click)の種類別に、 handle_event 関数を定義しています。
特定の値だけを更新したい場合には updateを、更新したい値を多く渡したい場合は assign を呼び出しています。

なお「 phx-click 」についてですが、こちらもLiveViewのバージョン0.1.2で 後方互換のない変更 が発生しています。
0.1.1までは「phx-value=1」のような形式でしたが、0.1.2以降では「phx-value-*」形式になっています。handle_event内での値の取り出し方も「*」に当たる部分を指定(例えば、「phx-value-decv」の場合、v["decv"]のように指定)して値を取り出すようになりました。

lib/hiyoko_web/router.ex
〜(略)〜
  scope "/", HiyokoWeb do
    pipe_through :browser

    get "/", PageController, :index
    live "/exercises", Exercises      #<- ここを追記
  end
〜(略)〜
lib/hiyoko_web/live/exercises.ex
defmodule HiyokoWeb.Exercises do
  use Phoenix.LiveView

  def render( assigns ) do
    ~L"""
      <h2>FizzBuzz  Fibonacci</h2>
      <p>
        <%= @message %>
      </p>
      <div>
        <h3>The count is: <%= @num %></h1>
        <button phx-click="deccalc" phx-value-decv=1>-(calc)</button>
        <button phx-click="dec" phx-value-decv=3>-</button>
        <button phx-click="clear" phx-value-clear=0>clear</button>
        <button phx-click="inc" phx-value-incv=4>+</button>
        <button phx-click="inccalc" phx-value-incv=1>+(calc)</button>
      </div>
      <table>
      <tr>
        <th>num</th>
        <th>FizzBuzz</th>
        <th>Fibonacci</th>
      </tr>
      <tr>
        <td><%= @num %></td>
        <td><%= @fzbz %></td>
        <td><%= @fibo %></td>
      </tr>
      </table>
    """
  end

  def mount( _session, socket ) do
    {:ok, assign( socket, message: "", num: 0, fzbz: 0, fibo: 0 ) }
  end

  def handle_event("inc", _, socket) do
    {:noreply, update(socket, :num, &(&1 + 1))}
  end

  def handle_event("dec", v, socket) do
    {:noreply, update(socket, :num, &(&1 - String.to_integer(v["decv"])))}
  end


  def handle_event("inccalc", v, socket) do
    add = fn(x, y) -> x + y end
    v1 = socket.assigns.num |> add.(String.to_integer(v["incv"]))
    {:noreply, assign(socket, message: "Calculation(add)", num: v1, fzbz: fizzbuzz(v1), fibo: fib(v1))}
  end

  def handle_event("clear", _, socket) do
    {:noreply, assign(socket, message: "Clear", num: 0, fzbz: 0, fibo: 0)}
  end

  def handle_event("deccalc", v, socket) do
    subtract = fn(x, y) -> x - y end
    v1 = socket.assigns.num |> subtract.(String.to_integer(v["decv"]))
    {:noreply, assign(socket, message: "Calculation(subtract)", num: v1, fzbz: fizzbuzz(v1), fibo: fib(v1))}
  end


  defp fizzbuzz(x) do
    fb = fn
      0, 0, _ -> "FizzBuzz"
      0, _, _ -> "Fizz"
      _, 0, _ -> "Buzz"
      _, _, i -> Integer.to_string(i)
    end
    fb.(rem(x,3), rem(x,5), x)
  end


  defp fib(0), do: 0
  defp fib(1), do: 1
  defp fib(x) when (x >=2) do
    fib(x-1) + fib(x-2)
  end
  defp fib(x) when (x < 0) do
    ax = abs(x)
    :math.pow(-1, ax+1) * fib(ax)
  end
end

実際に書いてみるとわかりますが、JavaScriptのコードを直接書かずにSPAのようなことができるのは、ちょっとした感動を与えてくれます。
フロントエンドのコードを意識せずに、サーバサイドだけで完結できるのは随分とお手軽です。

最後に宣伝

技術書典7(2019月9月22日)で、「 PhoenixLiveViewとNervesをさわるElixirへのいざない 」という本を頒布します。

タイトルの通り、Elixir界隈では最近注目の的である「 Phoenix LiveView 」と「 Nerves 」という二つのフレームワークについてさわってみようという趣旨の入門本となっています。

興味を持たれたら、ぜひお立ち寄りください。

執筆時期の関係上、LiveViewのバージョンについて「 0.1.1 」ベースの内容になっています。
LiveViewのバージョンを明示的に 0.1.1 に指定したい場合は、以下のようにすれば良いです。

mix.exs
{:phoenix_live_view, github: "phoenixframework/phoenix_live_view"},

の箇所を

mix.exs
{:phoenix_live_view, "0.1.1"},

に修正。

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