diff --git a/lib/flop_phoenix.ex b/lib/flop_phoenix.ex
index 8540482..0664eda 100644
--- a/lib/flop_phoenix.ex
+++ b/lib/flop_phoenix.ex
@@ -1025,6 +1025,12 @@ defmodule Flop.Phoenix do
will not be clickable.
"""
+ attr :directions, :any,
+ doc: """
+ An optional 2-element tuple used for custom ascending and descending sort
+ behavior for the column, i.e. `{:asc_nulls_last, :desc_nulls_first}`
+ """
+
attr :show, :boolean,
doc: """
Boolean value to conditionally show the column. Defaults to `true`
diff --git a/lib/flop_phoenix/table.ex b/lib/flop_phoenix/table.ex
index 281e62b..4dd3783 100644
--- a/lib/flop_phoenix/table.ex
+++ b/lib/flop_phoenix/table.ex
@@ -81,6 +81,7 @@ defmodule Flop.Phoenix.Table do
field={col[:field]}
label={col[:label]}
sortable={sortable?(col[:field], @meta.schema)}
+ directions={col[:directions]}
meta={@meta}
thead_th_attrs={
merge_attrs(@opts[:thead_th_attrs], col, :thead_th_attrs)
@@ -173,6 +174,7 @@ defmodule Flop.Phoenix.Table do
attr :target, :string, required: true
attr :sortable, :boolean, required: true
attr :thead_th_attrs, :list, required: true
+ attr :directions, :any
attr :symbol_asc, :any
attr :symbol_desc, :any
attr :symbol_unsorted, :any
@@ -183,11 +185,26 @@ defmodule Flop.Phoenix.Table do
direction = order_direction(assigns.meta.flop, assigns.field)
assigns = assign(assigns, :order_direction, direction)
+ sort_path_options =
+ if directions = assigns[:directions],
+ do: [directions: directions],
+ else: []
+
+ sort_path =
+ build_path(
+ assigns[:path],
+ assigns[:meta],
+ assigns[:field],
+ sort_path_options
+ )
+
+ assigns = assign(assigns, :sort_path, sort_path)
+
~H"""
<.sort_link
- path={build_path(@path, @meta, @field)}
+ path={@sort_path}
on_sort={@on_sort}
event={@event}
field={@field}
@@ -295,12 +312,17 @@ defmodule Flop.Phoenix.Table do
field in (module |> struct() |> Flop.Schema.sortable())
end
- defp build_path(nil, _, _), do: nil
+ defp build_path(nil, _, _, _), do: nil
- defp build_path(path, meta, field) do
+ defp build_path(
+ path,
+ meta,
+ field,
+ opts
+ ) do
Flop.Phoenix.build_path(
path,
- Flop.push_order(meta.flop, field),
+ Flop.push_order(meta.flop, field, opts),
backend: meta.backend,
for: meta.schema
)
diff --git a/mix.exs b/mix.exs
index 2a7c5ea..2c1c8f5 100644
--- a/mix.exs
+++ b/mix.exs
@@ -55,7 +55,7 @@ defmodule FlopPhoenix.MixProject do
{:ex_machina, "~> 2.4", only: :test},
{:excoveralls, "~> 0.10", only: :test},
{:floki, "~> 0.34.0", only: :test},
- {:flop, "~> 0.22.0"},
+ {:flop, "~> 0.23.0"},
{:jason, "~> 1.0", only: [:dev, :test]},
{:makeup_diff, "~> 0.1.0", only: :dev, runtime: false},
{:phoenix, "~> 1.6.0 or ~> 1.7.0"},
diff --git a/mix.lock b/mix.lock
index 1ca85ed..aa1e735 100644
--- a/mix.lock
+++ b/mix.lock
@@ -12,7 +12,7 @@
"excoveralls": {:hex, :excoveralls, "0.17.1", "83fa7906ef23aa7fc8ad7ee469c357a63b1b3d55dd701ff5b9ce1f72442b2874", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "95bc6fda953e84c60f14da4a198880336205464e75383ec0f570180567985ae0"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"floki": {:hex, :floki, "0.34.3", "5e2dcaec5d7c228ce5b1d3501502e308b2d79eb655e4191751a1fe491c37feac", [:mix], [], "hexpm", "9577440eea5b97924b4bf3c7ea55f7b8b6dce589f9b28b096cc294a8dc342341"},
- "flop": {:hex, :flop, "0.22.1", "4eb5dc1c159845e31d33cd8e73e249b84d013d3b9b1fb17619e70d55fbd2b025", [:mix], [{:ecto, "~> 3.10.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}], "hexpm", "2f212238d92a8fcc2adadf20dcd875c6f8b4e1ce38ca6bc3f805918a5be567e4"},
+ "flop": {:hex, :flop, "0.23.0", "68b07840df6dc6fc53682097f3838c8ea5b6806642c41651a2d5da85f7e676b1", [:mix], [{:ecto, "~> 3.10.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}], "hexpm", "0521d0cbd58433607b9e9c77e065cc00eeb6ffdacd8fa1ed009366386f72d6c0"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
"makeup_diff": {:hex, :makeup_diff, "0.1.0", "5be352b6aa6f07fa6a236e3efd7ba689a03f28fb5d35b7a0fa0a1e4a64f6d8bb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "186bad5bb433a8afeb16b01423950e440072284a4103034ca899180343b9b4ac"},
diff --git a/test/flop_phoenix_test.exs b/test/flop_phoenix_test.exs
index 1602dcf..32c36ab 100644
--- a/test/flop_phoenix_test.exs
+++ b/test/flop_phoenix_test.exs
@@ -2176,6 +2176,64 @@ defmodule Flop.PhoenixTest do
assert Jason.decode!(phx_click) == [["push", %{"event" => "sort"}]]
end
+ test "application of custom sort directions per column" do
+ assigns = %{
+ meta: %Flop.Meta{
+ flop: %Flop{
+ order_by: [:ttfb],
+ order_directions: [:desc_nulls_last]
+ }
+ },
+ items: [
+ %{
+ ttfb: 2
+ },
+ %{
+ ttfb: 1
+ },
+ %{
+ ttfb: nil
+ }
+ ],
+ ttfb_directions: {:asc_nulls_last, :desc_nulls_last}
+ }
+
+ html =
+ ~H"""
+
+ <:col
+ :let={navigation}
+ label="TTFB"
+ field={:ttfb}
+ directions={@ttfb_directions}
+ >
+ <%= navigation.ttfb %>
+
+
+ """
+ |> rendered_to_string()
+ |> Floki.parse_fragment!()
+
+ [ttfb_sort_href] =
+ html
+ |> Floki.find("thead th a:fl-contains('TTFB')")
+ |> Floki.attribute("href")
+
+ %URI{query: query} = URI.parse(ttfb_sort_href)
+ decoded_query = Query.decode(query)
+
+ # assert href representing opposite direction of initial table sort
+ assert %{
+ "order_by" => ["ttfb"],
+ "order_directions" => ["asc_nulls_last"]
+ } = decoded_query
+ end
+
test "supports a function/args tuple as path" do
html = render_table(%{path: {&route_helper/3, @route_helper_opts}})
assert [a] = Floki.find(html, "th a:fl-contains('Name')")
|