Packages
formex
0.2.1
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.10
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.3
0.3.2
0.3.1
0.3.0
0.2.3
0.2.2
0.2.1
0.2.0
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Form library for Phoenix with Ecto support
Current section
Files
Jump to
Current section
Files
lib/view.ex
defmodule Formex.View do
use Phoenix.HTML
alias Formex.Form
@moduledoc """
Helper functions for templating.
Example of use:
<%= formex_form_for @form, @action, fn f -> %>
<%= if @form.changeset.action do %>
<div class="alert alert-danger">
<p>Oops, something went wrong! Please check the errors below.</p>
</div>
<% end %>
<%= formex_rows f %>
<div class="form-group">
<%= submit "Submit", class: "btn btn-primary" %>
</div>
<% end %>
"""
@doc """
Works similar to a `Phoenix.HTML.Form.form_for/4`
In the callback function the first argument is `t:Formex.Form.t/0` instead of a
`t:Phoenix.HTML.Form.t/0`.
This argument contains the `t:Phoenix.HTML.Form.t/0` under a `:phoenix_form` key
"""
@spec formex_form_for(Form.t, String.t, Keyword.t (Formex.t -> Phoenix.HTML.unsafe))
:: Phoenix.HTML.safe
def formex_form_for(form, action, options \\ [], fun) do
Phoenix.HTML.Form.form_for(form.changeset, action, options, fn f ->
form
|> Map.put(:phoenix_form, f)
|> fun.()
end)
end
@doc """
Generates all `formex_row/2`s at once
"""
def formex_rows(form) do
Enum.map(form.fields, fn field ->
formex_row(form, field.name)
end)
end
@doc """
Generates all `formex_row_horizontal/2`s at once
"""
def formex_rows_horizontal(form) do
Enum.map(form.fields, fn field ->
formex_row_horizontal(form, field.name)
end)
end
#
@doc """
Generates a row with Bootstrap's `.form-group` class. Example of use:
<%= formex_row f, :title %>
<%= formex_row f, :content %>
<%= formex_row f, :category_id %>
"""
@spec formex_row(Form.t, Atom.t) :: Phoenix.HTML.safe
def formex_row(form, field_name) do
field = get_field(form, field_name)
field_html = generate_field_html(form, field)
label_html = generate_label_html(form, field)
field_html = attach_addon(field_html, field)
tags = [label_html, field_html]
|> attach_error(form, field)
wrapper_class = ["form-group"]
|> attach_error_class(form, field)
|> attach_required_class(field)
content_tag(:div, tags, class: Enum.join(wrapper_class, " "))
end
@doc """
Generates a row with Bootstrap's `.form-group` class. Should be used with `.form-horizontal` class.
<div class="form-horizontal">
<%= formex_row_horizontal f, :title %>
<%= formex_row_horizontal f, :content %>
<%= formex_row_horizontal f, :category_id %>
</div>
"""
@spec formex_row_horizontal(Form.t, Atom.t) :: Phoenix.HTML.safe
def formex_row_horizontal(form, field_name) do
field = get_field(form, field_name)
field_html = generate_field_html(form, field)
label_html = generate_label_html(form, field, "col-sm-2")
field_html = attach_addon(field_html, field)
tags = [field_html]
|> attach_error(form, field)
wrapper_class = ["form-group"]
|> attach_error_class(form, field)
|> attach_required_class(field)
column = content_tag(:div, tags, class: "col-sm-10")
content_tag(:div, [label_html, column], class: Enum.join(wrapper_class, " "))
end
#
@spec get_field(Form.t, Atom.t) :: Formex.Field.t
defp get_field(form, field_name) do
Enum.find(form.fields, fn field ->
field.name == field_name
end)
end
@spec generate_field_html(Form.t, Formex.Field.t) :: any
defp generate_field_html(form, field) do
type = field.type
opts = field.opts
data = field.data
phoenix_opts = if opts[:phoenix_opts], do: opts[:phoenix_opts], else: []
class = if opts[:class], do: opts[:class], else: ""
args = [form.phoenix_form, field.name]
args = args ++ cond do
Enum.member? [:select, :multiple_select], type ->
[data[:choices], Keyword.merge([class: class<>" form-control"], phoenix_opts) ]
Enum.member? [:checkbox], type ->
[Keyword.merge([class: class], phoenix_opts) ]
Enum.member? [:file_input], type ->
[Keyword.merge([class: class], phoenix_opts) ]
true ->
[Keyword.merge([class: class<>" form-control"], phoenix_opts) ]
end
input = apply(Phoenix.HTML.Form, type, args)
cond do
Enum.member? [:checkbox], type ->
content_tag(:div, [
content_tag(:label, [
input
])
], class: "checkbox")
true ->
input
end
end
@spec generate_label_html(Form.t, Formex.Field.t, String.t) :: Phoenix.HTML.safe
defp generate_label_html(form, field, class \\ "") do
Phoenix.HTML.Form.label(
form.phoenix_form,
field.name,
field.label,
class: "control-label "<>class
)
end
defp generate_error_field(form, field) do
text = Application.get_env(:formex, :translate_error).(form.phoenix_form.errors[field.name])
content_tag(:span, text, class: "help-block")
end
#
defp attach_addon(field_html, field) do
if field.opts[:addon] do
addon = content_tag(:div, field.opts[:addon], class: "input-group-addon")
content_tag(:div, [field_html, addon], class: "input-group" )
else
field_html
end
end
defp attach_error(tags, form, field) do
if form.phoenix_form.errors[field.name] do
tags ++ [generate_error_field(form, field)]
else
tags
end
end
defp attach_error_class(wrapper_class, form, field) do
if form.phoenix_form.errors[field.name] do
wrapper_class ++ ["has-error"]
else
wrapper_class
end
end
defp attach_required_class(wrapper_class, field) do
if field.required do
wrapper_class ++ ["required"]
else
wrapper_class
end
end
end