ExcelからElixir入門⑪：LiveView製のQiita検索SPAをフォームsubmitスタイルに換装

【本コラムは、3分で読めて、10分くらいでお試しいただけます】
[piacere](https://twitter.com/piacere_ex)です、ご覧いただいてありがとございます :bow:

[前回](https://qiita.com/piacere_ex/items/3f8ee18c9443d63955bf)に引き続き、Phoenix LiveViewのAPI無しSPAをいじっていきます

今回は、前回作った「Qiita検索（リアルタイム検索付き）」を、業務系のWebアプリではよくある、フォームsubmitスタイルに換装してみます

なお、[「Phoenix」](https://qiita.com/piacerex/items/b7787580fce5f148242f#phoenix%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)は、ElixirのWebフレームワークです

**■「ExcelからElixir入門」シリーズの目次**
[**①データ並替え／絞り込み**](https://qiita.com/piacere_ex/items/6714e1440e3f25fb46a1)
|> [**②データ列抽出、Web表示**](https://qiita.com/piacere_ex/items/b7787580fce5f148242f)
|> [<b>③WebにDBデータ表示</b>](https://qiita.com/piacere_ex/items/a7558adc6856e3577dc6)
|> [<b>④Webに外部APIデータ表示</b>](https://qiita.com/piacere_ex/items/4c212615a4eb699dd109)
|> [<b>⑤Webにグラフ表示</b>](https://qiita.com/piacere_ex/items/290b76b76d5ff8e019bf)
|> [**⑥SPAからPhoenix製APIを呼び出す（表示編）【LiveView版】**](https://qiita.com/piacerex/items/64e77b85bfb4c6832662)
|> [**⑦SPAからPhoenix製APIを呼び出す（更新編）【LiveView版】**](https://qiita.com/piacerex/items/78ee0d2ad8cca0927980)
|> [<b>⑧Gigalixirに本番リリース</b>](https://qiita.com/piacerex/items/1a9cbcc740ca3707eaec)
|> [**⑨Elixir／PhoenixのCRUD Webアプリをリリース**](https://qiita.com/piacerex/items/511f24888c7350639d0b)
|> [**⑩「LiveView」ElixirサーバサイドのみでReact的SPA／リアルタイムUIが作れる**](https://qiita.com/piacerex/items/3f8ee18c9443d63955bf)
|> [**⑪LiveView製Qiita検索SPAをフォームsubmitスタイルに換装**](https://qiita.com/piacerex/items/21b0e308a36e486d8b25)
|> [**⑫LiveViewのコード内HTMLをテンプレートファイルに分離**](https://qiita.com/piacerex/items/5b1aabb0c45bb9934bb9)
|> [**⑬ElixirサーバサイドSPAをスマホで見るためにGigalixirリリース**](https://qiita.com/piacerex/items/583174d72e6fc0cd289e)
|> [**⑭Gigalixir上のLiveViewアプリに独自ドメイン名を付与して正式なアプリ公開**](https://qiita.com/piacerex/items/b61348c282395167fd8c)

# submit用ハンドラに書き換える

[前回のハンドラ](https://qiita.com/piacere_ex/items/3f8ee18c9443d63955bf#liveview%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%8F%E3%83%B3%E3%83%89%E3%83%A9)は、以下の通り、「phx-change」を使った、リアルタイム入力の都度、Qiita APIを呼び出すようなハンドラでした

```elixir:lib/basic_web/live/qiita_search_realtime.ex
defmodule BasicWeb.QiitaSearchRealtime do
  use Phoenix.LiveView

  def render(assigns) do
    ~L"""
    …
    <form phx-change="change">
    <input type="text" name="query" value="<%= @query %>" placeholder="empty" />
…
```

これを、submitボタンクリック時にQiita APIを呼び出すようなハンドラへと変更します

`phx-submit` を使うと、submit時のみ処理を行うようにできるので、submitボタンを追加してみます

ついでに、Qiita API検索中は、フォーム操作をできなくするため、`loading` というUI制御フラグも導入します

なお、`handle_event("change", ～` は、今回の換装で、利用されなくなります

```elixir:lib/basic_web/live/qiita_search_realtime.ex
defmodule BasicWeb.QiitaSearchRealtime do
  use Phoenix.LiveView

  def render(assigns) do
    ~L"""
      <p>
      <%= if @message do %><%= @message %><% end %>
      </p>

      <!-- modify here---v -->
      <form phx-submit="submit">
      <input type="text" name="query" value="<%= @query %>" placeholder="empty" <%= if @loading, do: "readonly" %> />
      Query: <%= @query %><br>
      <input type="submit" value="search" onclick="blur()" <%= if @loading, do: "readonly" %> />
      </form>

      <table>
      <tr>
        <th>ID</th>
        <th>タイトル</th>
        <th>作成日</th>
      </tr>
      <%= for result <- @results do %>
      <tr>
        <td><%= result["id"] %></td>
        <td><%= result["title"] %></td>
        <td><%= result["created_at"] %></td>
      </tr>
      <% end %>
      </table>
    """
  end

  def mount(_params, _session, socket) do
    {:ok, assign(socket, query: "", message: "[Init]", loading: false, results: [])}
  end

  def handle_event("change", %{"query" => query}, socket) do
    send(self(), {:submit, query})
    {:noreply, assign(socket, query: query, message: "")}
  end

  def handle_event("submit",  %{"query" => query}, socket) do
    send(self(), {:submit, query})
    {:noreply, assign(socket, query: query, message: "[Searching...]", loading: true)}
  end

  def handle_info({:submit, query}, socket) do
    results = Req.get!("https://qiita.com/api/v2/items?query=#{query}").body
    {:noreply, assign(socket, query: query, message: "[Complete!!]", loading: false, results: results)}
  end
end
```

ブラウザで「``http://localhost:4000/realtime``」にアクセスすると、submitボタンが付いたQiita検索SPA画面が表示されます
![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/eb8f0b97-4fbf-3e74-1919-c2bc68bcbe07.png)

submitボタンクリックで、Qiita検索が実行されるようになります
![image.png](https://qiita-image-store.s3.amazonaws.com/0/155423/eab13587-1f1e-8291-738a-5eced8f47aff.png)

# リアルタイム入力とsubmitを混在させる

「phx-change」と「phx-submit」を混在させることもできます

テキスト入力の内容は、「phx-change」で画面上の検索文字列をリアルタイム更新し、submitボタンは「phx-submit」でsubmitできるようにしてみます

具体的には、formに「phx-change="change"」を追加し、「handle_event("change", ～」から「send(self(), {:submit, query})」を削除（コメントアウト）します

```elixir:lib/basic_web/live/qiita_search_realtime.ex
defmodule BasicWeb.QiitaSearchRealtime do
  use Phoenix.LiveView
	def render(assigns) do
		~L"""
		…
		<!-- modify here-----------v -->
        <form phx-submit="submit" phx-change="change">
        …
        """
    end
…
	def handle_event("change", %{"query" => query}, socket) do
		#send(self(), {:submit, query})  # <-- comment-out here
		{:noreply, assign(socket, query: query, message: "")}
	end
 …
```

これで、検索文字列はリアルタイム反映される一方、Qiita検索は、submitボタンクリック時のみ実行されます

# 【参考】本コラムの検証環境

本コラムは、以下環境で検証しています（恐らくUbuntu実機やMacでも動きます）

- Windows 10
  - 実機＋Elixir 1.14.2 (Erlang/OTP 25)
    - Phoenix 1.6.15
  - WSL2／Ubuntu 20.04＋Elixir 1.14.2 (Erlang/OTP 25)　※[**最新版のインストール手順はコチラ**](https://qiita.com/piacerex/items/01e89435af0f7a454ad2)
    - Phoenix 1.6.15
  - Docker／Debian 11.6＋Elixir 1.14.2 (Erlang/OTP 25)
    - Phoenix 1.6.15

- Windows11
  - WSL2／Ubuntu 22.04＋Docker Compose＋Elixir 1.13.4 (Erlang/OTP 25)
    - Phoenix 1.6.15

# 終わり

今回は、LiveViewでのフォームsubmitについて解説しました

業務系のWebアプリでは、submitボタンによる確定や更新がポピュラーなため、今回の書き方をご参考ください

また、submitとリアルタイム入力の混在についても解説しましたが、これらを混在させるモダン業務系Webアプリでは、応用が効くテクニックかと思います

[次回は、**LiveView用のHTMLをテンプレートファイルに分離** します](https://qiita.com/piacerex/items/5b1aabb0c45bb9934bb9)