defmodule Formulator do use Phoenix.HTML alias Formulator.HtmlError import Formulator.Input @doc """ Returns an html input with an associated label. If there are errors associated with the field, it will also output a span tag with the errors. ## Options * `:label` - When given a keyword list, the keyword `text` is extracted to use as the label text. All other options are passed along to the label. When given `false`, does not create a label tag. Instead, an `aria-label` attribute is added to the input to improve accessibility. * `:validate` - Defaults to application config. When provided a form created with an Ecto changeset that contains validations, then Formulator will add HTML5 validation attributes (except regex). * `:validate_regex` - Defaults to application config. Like option `:validate`, except this will add a pattern HTML5 validation. This should work with most simple regex patterns, but the browser's regex engine may differ from Erlang's. * `:wrapper_class` - This allows you to add a class to the div that wraps the input and label. This can also be set in your config: `config :formulator, wrapper_class: "input-wrapper"` ## Examples Basic input: <%= input form, :name %> #=>
#=> #=> #=>
Without a label: <%= input form, :name, label: false %> #=>
#=> #=>
Passing other options: <%= input form, :name, label: [class: "control-label"] %> #=>
#=> #=> #=>
Using different input types: <%= input form, :email_address, as: :email, placeholder: "your@email.com", class: "my-email-class", label: [class: "my-email-label-class"] %> #=>
#=> #=> #=>
Or a number input: <%= input form, :count, as: :number %> #=>
#=> #=> #=>
If your form is using a changeset with validations (eg, with `Ecto` and `phoenix_ecto`), then Formulator will add HTML5 validation attributes: <%= input form, :email, as: :email %> #=>
#=> #=> #=>
If you would rather not add HTML5 validation attributes, you can opt out by supplying `validate: false`: <%= input form, :email, as: :email, validate: false %> #=>
#=> #=> #=>
You may want HTML5 validations, but the browser's regex engine is not working with Elixir's regex engine. You can opt-out of regex validation with `validate_regex: false`: <%= input form, :email, as: :email, validate_regex: false %> #=>
#=> #=> #=>
""" @spec input(Phoenix.HTML.Form.t, atom, []) :: binary def input(form, field, options \\ []) do {label_options, options} = extract_label_options(options) input_wrapper form, field, options, label_options, fn error -> build_input(form, field, options, error) end end defp input_wrapper(form, field, options, label_options, fun) do [ content_tag( :div, build_input_and_associated_tags(form, field, label_options, fun), class: wrapper_class(options) ) ] end defp build_input_and_associated_tags(form, field, label_options, fun) do error = HtmlError.html_error(form, field) [ build_label(form, field, label_options), fun.(error), error.html ] |> Enum.reject(&(is_nil(&1))) end defp wrapper_class(options) do options[:wrapper_class] || Application.get_env(:formulator, :wrapper_class) end defp extract_label_options(options) do label_options = options |> Keyword.get(:label, []) options = options |> Keyword.delete(:label) {label_options, options} end def build_label(_form, _field, false), do: nil def build_label(form, field, label_text) when is_binary(label_text) do build_label(form, field, [text: label_text]) end def build_label(form, field, label_options) do case label_options[:text] do nil -> label(form, field, label_options) text -> label(form, field, text, label_options |> Keyword.delete(:text)) end end end