Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle filter label duplicates #89

Merged
merged 8 commits into from
Sep 21, 2022
49 changes: 36 additions & 13 deletions lib/flop_phoenix.ex
Original file line number Diff line number Diff line change
Expand Up @@ -668,14 +668,7 @@ defmodule Flop.Phoenix do
def filter_fields(assigns) do
is_meta_form!(assigns.form)
fields = assigns[:fields] || []

labels =
fields
|> Enum.map(fn
{field, opts} -> {field, opts[:label]}
field -> {field, nil}
end)
|> Enum.reject(fn {_, label} -> is_nil(label) end)
labels = get_filter_labels(assigns, fields)

types =
fields
Expand All @@ -698,15 +691,34 @@ defmodule Flop.Phoenix do

~H"""
<%= filter_hidden_inputs_for(@form) %>
<%= for ff <- inputs_for(@form, :filters, fields: @fields, id: @id) do %>
<%= for {ff, label} <- inputs_for(@form, :filters, fields: @fields, id: @id) |> Enum.zip(@labels) do %>
<%= render_slot(@inner_block, %{
label: ~H"<.filter_label form={ff} texts={@labels} {@label_opts} />",
label: ~H"<.filter_label form={ff} texts={label} {@label_opts} />",
input: ~H"<.filter_input form={ff} types={@types} {@input_opts} />"
}) %>
<% end %>
"""
end

defp get_filter_labels(%{dynamic: true, form: form}, fields) do
dynamic_filters =
Enum.map(form.data.filters, fn %Flop.Filter{field: field} -> field end)

fields
|> Enum.map(fn
{field, opts} -> {field, opts[:label]}
field -> {field, nil}
end)
|> Enum.reject(fn {field, _} -> field not in dynamic_filters end)
end

defp get_filter_labels(_, fields) do
Enum.map(fields, fn
{field, opts} -> {field, opts[:label]}
field -> {field, nil}
end)
end

@doc """
Renders a label for the `:value` field of a filter.

Expand Down Expand Up @@ -778,16 +790,27 @@ defmodule Flop.Phoenix do
"""
end

defp label_text(form, nil), do: form |> input_value(:field) |> humanize()
defp label_text(form, {_field, nil}) do
form |> input_value(:field) |> humanize()
end

defp label_text(form, func) when is_function(func, 1),
do: form |> input_value(:field) |> func.()
defp label_text(form, value) when value in [nil, []] do
form |> input_value(:field) |> humanize()
end

defp label_text(form, func) when is_function(func, 1) do
form |> input_value(:field) |> func.()
end

defp label_text(form, mapping) when is_list(mapping) do
field = input_value(form, :field)
safe_get(mapping, field, label_text(form, nil))
end

defp label_text(_form, {_, label}) do
label
end

defp safe_get(keyword, key, default)
when is_list(keyword) and is_atom(key) do
Keyword.get(keyword, key, default)
Expand Down
34 changes: 34 additions & 0 deletions test/flop_phoenix_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2271,6 +2271,40 @@ defmodule Flop.PhoenixTest do
assert Floki.attribute(input, "type") == ["tel"]
end

test "renders custom labels for identical field inputs", %{
meta: meta
} do
fields = [
{:email, [label: "E-mail"]},
{:email, [label: "Second E-mail"]}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the test to also set different input types and different operators?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this does not work with different input types yet

]

html =
form_to_html(meta, fn f ->
(&filter_fields/1)
|> render_component(
__changed__: %{},
form: f,
fields: fields,
input_opts: [class: "input"],
label_opts: [class: "label"],
inner_block: %{
inner_block: fn _, e ->
[
e.label |> rendered_to_string() |> raw(),
e.input |> rendered_to_string() |> raw()
]
end
}
)
|> raw()
end)

# labels
assert [label] = Floki.find(html, "label[for='flop_filters_1_value']")
assert Floki.text(label) == "Second E-mail"
end

@tag capture_log: true
test "renders the labels and filter inputs with errors", %{
fields: fields
Expand Down