Formex is an extensible form library for Phoenix. With this library you don't write changeset (as in Ecto), but a separate module that declares fields of form (like in Symfony).
You can also use it with Ecto - see formex_ecto. That library will build changeset and additional Ecto queries for itself.
Formex doesn't validate data for itself - it uses validation libraries instead.
Formex comes with helper functions for templating. For now there is only a Bootstrap 3 form template, but you can easily create your own templates.
In addition to the main library, you have to install some validator adapter. In this example we will use Vex. List of available adapters
mix.exs
def deps do
[{:formex, "~> 0.6.0"},
{:formex_vex, "~> 0.1.0"}]
end
def application do
[applications: [:formex]]
endconfig/config.exs
config :formex,
validator: Formex.Validator.Vex,
translate_error: &AppWeb.ErrorHelpers.translate_error/1, # optional, from /lib/app_web/views/error_helpers.ex
template: Formex.Template.BootstrapHorizontal, # optional, can be overridden in a template
template_options: [ # optional, can be overridden in a template
left_column: "col-sm-2",
right_column: "col-sm-10"
]web/web.ex
def controller do
quote do
use Formex.Controller
end
end
def view do
quote do
use Formex.View
end
endLet's create a form for article.
# /web/model/article.ex
defmodule App.Article do
defstruct [:title, :content, :hidden]
end# /web/form/article_type.ex
defmodule App.ArticleType do
use Formex.Type
def build_form(form) do
form
|> add(:title, :text_input, label: "Title", validation: [presence: true])
|> add(:content, :textarea, label: "Content", phoenix_opts: [
rows: 4
], validation: [presence: true])
|> add(:hidden, :checkbox, label: "Is hidden?", required: false)
|> add(:save, :submit, label: "Submit", phoenix_opts: [
class: "btn-primary"
])
end
endPlease note that required option is used only to generate an asterisk.
Any validation must be done via validation option.
The :text_input and so on are function names from
Phoenix.HTML.Form
def new(conn, _params) do
form = create_form(App.ArticleType, %Article{})
render(conn, "form.html", form: form)
end
def create(conn, %{"article" => article_params}) do
App.ArticleType
|> create_form(%Article{}, article_params)
|> handle_form
|> case do
{:ok, article} ->
# do something with a new article struct
{:error, form} ->
# display errors
render(conn, "form.html", form: form)
end
endform.html.eex
<%= formex_form_for @form, article_path(@conn, :create), [class: "form-horizontal"], fn f -> %>
<%= if @form.submitted? do %>Oops, something went wrong!<% end %>
<%= formex_row f, :title %>
<%= formex_row f, :content %>
<%= formex_row f, :hidden %>
<%= formex_row f, :save %>
<%# or generate all fields at once: formex_rows f %>
<% end %>Put an asterisk to required fields:
.required .control-label:after {
content: '*';
margin-left: 3px;
}The final effect after submit:
- Creating forms
- Usage in a controller
- Usage in a template
- Validation
- Nested forms
- Collections of forms
- Add new items to collection on the backend
- Using a select picker plugin with ajax search
- Uploading files with Arc.Ecto (Formex.Ecto)
- formex_ecto - Ecto integration
- formex_vex - Vex
- formex_ecto - Ecto.Changeset

