엘릭서 피닉스 폼 필드 원 라이너

21103 단어 phoenixelixircssbulma

Necessity is the mother of invention.



フォームのスタイリングを抽象化する方法はいくつかありますが、個人的にフォームフィールドはヘルパー関数を自作するのが一番シンプルな気がしており、実際にやってみた結果も気に入ってます.

やりたいこと


  • 各foomfiーrdを一行で書けるようにしたい.

  • 예를 들어, mix phx.gen.auth コマンドで生成される以下のようなフォームフィールドがあります.

    <%= label f, :email %>
    <%= email_input f, :email, required: true %>
    <%= error_tag f, :email %>
    


    それを このように共通のCSSクラスも含め一行で簡潔に記述したいのです.

    <%= bulma_input f, :email %>
    


    動作環境




    elixir          1.13.4-otp-24
    erlang          24.3.4
    



    ❯ mix phx.new --version
    Phoenix installer v1.6.8
    


    아이데아



    카스탐 뷰헤르파를 기록할 수 있는 방법에 대한 지식과 아이데아는 Elixir言語의 작가 José Valimさんがこの記事( Dynamic forms with Phoenix )の中で丁寧に解説してくれています.
    ですのでそれを読めば大体わかります.

    また、 Phoenix 자가가 Phoenix.HTML.Form 等 ビルトインのヘルパー関数を多数持っているのでそれらを大いに活用することも大事だと思います.

    やってみる


    lib/my_app_web/views/input_helpers.exファイルを作成.

    defmodule MyAppWeb.InputHelpers do
      use Phoenix.HTML
    
      # TODO: define my custom view helper functions
    end
    

    lib/my_app_web.exview_helpers関数でそれを忘れずにinportしておく.

       defp view_helpers do
         quote do
           # Use all HTML functionality (forms, tags, etc)
           use Phoenix.HTML
    
           # Import LiveView and .heex helpers (live_render, live_patch, <.form>, etc)
           import Phoenix.LiveView.Helpers
           import MyAppWeb.LiveHelpers
    
           # Import basic rendering functionality (render, render_layout, etc)
           import Phoenix.View
    
    +      import MyAppWeb.InputHelpers
           import MyAppWeb.ErrorHelpers
           import MyAppWeb.Gettext
           alias MyAppWeb.Router.Helpers, as: Routes
         end
       end
    


    あとは MyAppWeb.InputHelpersに好きなようにヘルパー関数を定義するだけ.
    先日たまたま Bulma CSS 플레임워크를 사용하기 위해 시간에, 사용하기 위해 한 가지 작업을 하기 위해 사용했습니다.
    一つの三プルコードになるかもしれません.

    defmodule MyAppWeb.InputHelpers do
      use Phoenix.HTML
    
      def bulma_input(form, field, opts \\ []) do
        label_opts = Keyword.take(opts, ~w[required label]a)
        input_opts = Keyword.drop(opts, ~w[required label]a)
    
        content_tag :div, class: "field" do
          [
            build_label(form, field, label_opts),
            build_input(form, field, input_opts),
            MyAppWeb.ErrorHelpers.error_tag(form, field)
          ]
        end
      end
    
      def bulma_checkbox(form, field, opts \\ []) do
        content_tag :label, class: "checkbox" do
          [
            checkbox(form, field, opts),
            ' ',
            opts[:label] || field |> to_string() |> Phoenix.Naming.humanize()
          ]
        end
      end
    
      defp build_label(form, field, opts) do
        required = opts[:required] || Keyword.get(input_validations(form, field), :required)
        label_text = (opts[:label] || humanize(field)) <> if required, do: " *", else: ""
    
        Phoenix.HTML.Form.label(form, field, label_text, class: "label")
      end
    
      defp build_input(form, field, opts) do
        input_fun_name = opts[:using] || Phoenix.HTML.Form.input_type(form, field)
        permitted_attributes = Keyword.drop(opts, [:using])
    
        input_class =
          case input_fun_name do
            :textarea -> "textarea "
            _ -> "input "
          end <> form_state_class(form, field)
    
        input_opts =
          [{:class, input_class} | permitted_attributes]
          |> Enum.reject(&is_nil(elem(&1, 1)))
    
        content_tag :div, class: "control" do
          apply(Phoenix.HTML.Form, input_fun_name, [form, field, input_opts])
        end
      end
    
      defp form_state_class(form, field) do
        cond do
          # Some forms may not use a Map as a source. E.g., :user
          !is_map(form.source) -> ""
          # Ignore Conn-based form.
          Map.get(form.source, :__struct__) == Plug.Conn -> ""
          # The form is not yet submitted.
          !Map.get(form.source, :action) -> ""
          # This field has an error.
          form.errors[field] -> "is-danger"
          true -> "is-success"
        end
      end
    end
    

    lib/my_app_web/views/error_helpers.exPhoenixが生成した error_tagがあるので、そこのCSS クラスも必要に応じて変更します.

       def error_tag(form, field) do
         Enum.map(Keyword.get_values(form.errors, field), fn error ->
           content_tag(:span, translate_error(error),
    -       class: "invalid-feedback",
    +       class: "invalid-feedback help is-danger",
             phx_feedback_for: input_name(form, field)
           )
         end)
    


    Bulmaでスタイリングされたォームフィールドを生成する bulma_input関数ができました.

    bulma_input f, :email
    


    사용하는 Phoenix.HTML.Form の関数を切り替えるoption も受け付けます.

    # Phoenix.HTML.Form.text_input/3の代わりにPhoenix.HTML.Form.textarea/3を使用したい場合
    bulma_input f, :email, using: :textarea
    


    HTML 属性を追加できるようにしました.

    bulma_input f, :email, placeholder: "E-mail", autocomplete: "off"
    


    IEx로 전환



    TEN 플레이 톤의 폼으로 IEx上でランできる方法を探しました.

    Phoenixのソースコードのテストの中にヒントがあったので、その知識で適当にfォームを生成します.

    iex
    
    alias MyAppWeb.Accounts
    alias MyAppWeb.Accounts.User
    
    changeset = Accounts.change_user_registration(%User{})
    form = Phoenix.HTML.Form.form_for(changeset, "/registration", [])
    
    bulma_input(form, :email, placeholder: "E-mail", autocomplete: "off")
    |> Phoenix.HTML.Safe.to_iodata()
    |> to_string()
    |> IO.puts()
    



    <div class="field">
      <label class="label" for="user_email">Email *</label>
      <div class="control">
        <input autocomplete="off" class="input " id="user_email" name="user[email]" placeholder="E-mail" type="email">
      </div>
    </div>
    


    🎉

    Elixir코뮤니티에 더 나아가는 방법은 下記가 오스스메입니다



    Elixir코뮤니티 の歩き方 -国内온라인編-
    https://speakerdeck.com/elijo/elixirkomiyunitei-falsebu-kifang-guo-nei-onrainbian



    日本には28箇所のElixir코뮤니티가あります


    日程から イベントを探すなら Elixir イベントカレンダー📆



    ** Elixir아이벤트카렌다 **
    https://elixir-jp-calendar.fly.dev/

    좋은 웹페이지 즐겨찾기