` if `true`.
Default: `#{inspect(@default_table_opts[:container])}`.
- `:container_attrs` - The attributes for the table container.
Default: `#{inspect(@default_table_opts[:container_attrs])}`.
- `:no_results_content` - Any content that should be rendered if there are no
results. Default: `
No results.
`.
- `:thead_tr_attrs`: Attributes to added to each `
` tag within the
``. Default: `#{inspect(@default_table_opts[:thead_tr_attrs])}`.
- `:thead_th_attrs`: Attributes to added to each `` tag within the
``. Default: `#{inspect(@default_table_opts[:thead_th_attrs])}`.
- `:tbody_tr_attrs`: Attributes to added to each `` tag within the
` |
`. Default: `#{inspect(@default_table_opts[:tbody_tr_attrs])}`.
- `:tbody_td_attrs`: Attributes to added to each `` tag within the
` | `. Default: `#{inspect(@default_table_opts[:tbody_td_attrs])}`.
See the module documentation for examples.
"""
@doc since: "0.6.0"
@doc section: :generators
@spec table(map) :: Phoenix.LiveView.Rendered.t()
def table(assigns) do
assigns =
Map.update(
assigns,
:opts,
@default_table_opts,
&Keyword.merge(@default_table_opts, &1)
)
~L"""
<%= if @items == [] do %>
<%= @opts[:no_results_content] %>
<% else %>
<%= if @opts[:container] do %>
<%= content_tag :div, @opts[:container_attrs] do %>
<%= Table.render(assigns) %>
<% end %>
<% else %>
<%= Table.render(assigns) %>
<% end %>
<% end %>
"""
end
@doc """
Converts a Flop struct into a keyword list that can be used as a query with
Phoenix route helper functions.
Default limits and default order parameters set via the application
environment are omitted. You can pass the `:for` option to pick up the
default options from a schema module deriving `Flop.Schema`. You can also
pass `default_limit` and `default_order` as options directly. The function
uses `Flop.get_option/2` internally to retrieve the default options.
## Examples
iex> to_query(%Flop{})
[]
iex> f = %Flop{order_by: [:name, :age], order_directions: [:desc, :asc]}
iex> to_query(f)
[order_directions: [:desc, :asc], order_by: [:name, :age]]
iex> f |> to_query |> Plug.Conn.Query.encode()
"order_directions[]=desc&order_directions[]=asc&order_by[]=name&order_by[]=age"
iex> f = %Flop{page: 5, page_size: 20}
iex> to_query(f)
[page_size: 20, page: 5]
iex> f = %Flop{first: 20, after: "g3QAAAABZAAEbmFtZW0AAAAFQXBwbGU="}
iex> to_query(f)
[first: 20, after: "g3QAAAABZAAEbmFtZW0AAAAFQXBwbGU="]
iex> f = %Flop{
...> filters: [
...> %Flop.Filter{field: :name, op: :=~, value: "Mag"},
...> %Flop.Filter{field: :age, op: :>, value: 25}
...> ]
...> }
iex> to_query(f)
[
filters: %{
0 => %{field: :name, op: :=~, value: "Mag"},
1 => %{field: :age, op: :>, value: 25}
}
]
iex> f |> to_query() |> Plug.Conn.Query.encode()
"filters[0][field]=name&filters[0][op]=%3D~&filters[0][value]=Mag&filters[1][field]=age&filters[1][op]=%3E&filters[1][value]=25"
iex> f = %Flop{page: 5, page_size: 20}
iex> to_query(f, default_limit: 20)
[page: 5]
"""
@doc since: "0.6.0"
@doc section: :miscellaneous
@spec to_query(Flop.t()) :: keyword
def to_query(%Flop{filters: filters} = flop, opts \\ []) do
filter_map =
filters
|> Stream.with_index()
|> Enum.into(%{}, fn {filter, index} ->
{index, Map.from_struct(filter)}
end)
keys = [
:after,
:before,
:first,
:last,
:offset,
:page
]
default_limit = Flop.get_option(:default_limit, opts)
default_order = Flop.get_option(:default_order, opts)
keys
|> Enum.reduce([], &maybe_add_param(&2, &1, Map.get(flop, &1)))
|> maybe_add_param(:page_size, flop.page_size, default_limit)
|> maybe_add_param(:limit, flop.limit, default_limit)
|> maybe_add_order_params(flop, default_order)
|> maybe_add_param(:filters, filter_map)
end
defp maybe_add_param(params, key, value, default \\ nil)
defp maybe_add_param(params, _, nil, _), do: params
defp maybe_add_param(params, _, [], _), do: params
defp maybe_add_param(params, _, map, _) when map == %{}, do: params
defp maybe_add_param(params, :page, 1, _), do: params
defp maybe_add_param(params, :offset, 0, _), do: params
defp maybe_add_param(params, _, val, val), do: params
defp maybe_add_param(params, key, val, _), do: Keyword.put(params, key, val)
defp maybe_add_order_params(
params,
%Flop{order_by: order_by, order_directions: order_directions},
%{order_by: order_by, order_directions: order_directions}
),
do: params
defp maybe_add_order_params(
params,
%Flop{order_by: order_by, order_directions: order_directions},
_
) do
params
|> maybe_add_param(:order_by, order_by)
|> maybe_add_param(:order_directions, order_directions)
end
@doc """
Takes a Phoenix path helper function and a list of path helper arguments and
builds a path that includes query parameters for the given `Flop` struct.
Default values for `limit`, `page_size`, `order_by` and `order_directions` are
omit from the query parameters. To pick up the default parameters from a
schema module deriving `Flop.Schema`, you need to pass the `:for` option.
## Examples
iex> pet_path = fn _conn, :index, query ->
...> "/pets?" <> Plug.Conn.Query.encode(query)
...> end
iex> flop = %Flop{page: 2, page_size: 10}
iex> build_path(pet_path, [%Plug.Conn{}, :index], flop)
"/pets?page_size=10&page=2"
We're defining fake path helpers for the scope of the doctests. In a real
Phoenix application, you would pass something like `&Routes.pet_path/3` as the
first argument.
You can also pass a `Flop.Meta` struct or a keyword list as the third
argument.
iex> pet_path = fn _conn, :index, query ->
...> "/pets?" <> Plug.Conn.Query.encode(query)
...> end
iex> flop = %Flop{page: 2, page_size: 10}
iex> meta = %Flop.Meta{flop: flop}
iex> build_path(pet_path, [%Plug.Conn{}, :index], meta)
"/pets?page_size=10&page=2"
iex> query_params = to_query(flop)
iex> build_path(pet_path, [%Plug.Conn{}, :index], query_params)
"/pets?page_size=10&page=2"
If the path helper takes additional path parameters, just add them to the
second argument.
iex> user_pet_path = fn _conn, :index, id, query ->
...> "/users/\#{id}/pets?" <> Plug.Conn.Query.encode(query)
...> end
iex> flop = %Flop{page: 2, page_size: 10}
iex> build_path(user_pet_path, [%Plug.Conn{}, :index, 123], flop)
"/users/123/pets?page_size=10&page=2"
If the last path helper argument is a query parameter list, the Flop
parameters are merged into it.
iex> pet_url = fn _conn, :index, query ->
...> "https://pets.flop/pets?" <> Plug.Conn.Query.encode(query)
...> end
iex> flop = %Flop{order_by: :name, order_directions: [:desc]}
iex> build_path(pet_url, [%Plug.Conn{}, :index, [user_id: 123]], flop)
"https://pets.flop/pets?user_id=123&order_directions[]=desc&order_by=name"
iex> build_path(
...> pet_url,
...> [%Plug.Conn{}, :index, [category: "small", user_id: 123]],
...> flop
...> )
"https://pets.flop/pets?category=small&user_id=123&order_directions[]=desc&order_by=name"
"""
@doc since: "0.6.0"
@doc section: :miscellaneous
@spec build_path(function, [any], Meta.t() | Flop.t() | keyword, keyword) ::
String.t()
def build_path(path_helper, args, meta_or_flop_or_params, opts \\ [])
def build_path(path_helper, args, %Meta{flop: flop}, opts),
do: build_path(path_helper, args, flop, opts)
def build_path(path_helper, args, %Flop{} = flop, opts) do
build_path(path_helper, args, Flop.Phoenix.to_query(flop, opts))
end
def build_path(path_helper, args, flop_params, _opts)
when is_function(path_helper) and
is_list(args) and
is_list(flop_params) do
final_args =
case Enum.reverse(args) do
[last_arg | rest] when is_list(last_arg) ->
query_arg = Keyword.merge(last_arg, flop_params)
Enum.reverse([query_arg | rest])
_ ->
args ++ [flop_params]
end
apply(path_helper, final_args)
end
end