Flop.Phoenix (Flop Phoenix v0.10.0) View Source

Components for Phoenix and Flop.

Introduction

Please refer to the Readme for an introduction.

Customization

The default classes, attributes, texts and symbols can be overridden by passing the opts assign. Since you probably will use the same opts in all your templates, you can globally configure an opts provider function for each component.

The functions have to return the options as a keyword list. The overrides are deep-merged into the default options.

defmodule MyAppWeb.ViewHelpers do
  import Phoenix.HTML

  def pagination_opts do
     [
      ellipsis_attrs: [class: "ellipsis"],
      ellipsis_content: "‥",
      next_link_attrs: [class: "next"],
      next_link_content: next_icon(),
      page_links: {:ellipsis, 7},
      pagination_link_aria_label: &"#{&1}ページ目へ",
      previous_link_attrs: [class: "prev"],
      previous_link_content: previous_icon()
    ]
  end

  defp next_icon do
    tag :i, class: "fas fa-chevron-right"
  end

  defp previous_icon do
    tag :i, class: "fas fa-chevron-left"
  end

  def table_opts do
    [
      container: true,
      container_attrs: [class: "table-container"],
      no_results_content: content_tag(:p, do: "Nothing found."),
      table_attrs: [class: "table"]
    ]
  end
end

Refer to pagination_option/0 and table_option/0 for a list of available options and defaults.

Once you have defined these functions, you can reference them with a module/function tuple in config/config.exs.

config :flop_phoenix,
  pagination: [opts: {MyApp.ViewHelpers, :pagination_opts}],
  table: [opts: {MyApp.ViewHelpers, :table_opts}]

Hiding default parameters

Default values for page size and ordering are omitted from the query parameters. If you pass the :for assign, the Flop.Phoenix function will pick up the default values from the schema module deriving Flop.Schema.

LiveView

The functions in this module can be used in both .eex and .heex templates.

Links are generated with Phoenix.LiveView.Helpers.live_patch/2. This will lead to <a> tags with data-phx-link and data-phx-link-state attributes, which will be ignored outside of LiveViews and LiveComponents.

When used in LiveView templates, you will need to handle the new params in the handle_params/3 callback of your LiveView module.

Event Based Pagination and Sorting

To make Flop.Phoenix use event based pagination and sorting, you need to assign the :event to the pagination and table generators. This will generate an <a> tag with phx-click and phx-value attributes set.

You can set a different target by assigning a :target. The value will be used in the phx-target attribute.

<Flop.Phoenix.pagination
  for={MyApp.Pet}
  meta={@meta}
  path_helper={&Routes.pet_path/4}
  path_helper_args{[@conn, :index, @owner]}
  event="paginate-pets"
  target={@myself}
/>

You will need to handle the event in the handle_event/3 callback of your LiveView module. The event name will be the one you set with the :event option.

def handle_event("paginate-pets", %{"page" => page}, socket) do
  flop = Flop.set_page(socket.assigns.meta.flop, page)

  with {:ok, {pets, meta}} <- Pets.list_pets(params) do
    {:noreply, assign(socket, pets: pets, meta: meta)}
  end
end

def handle_event("order_pets", %{"order" => order}, socket) do
  flop = Flop.push_order(socket.assigns.meta.flop, order)

  with {:ok, {pets, meta}} <- Pets.list_pets(flop) do
    {:noreply, assign(socket, pets: pets, meta: meta)}
  end
end

Link to this section Summary

Types

Defines the available options for Flop.Phoenix.pagination/1.

Defines the available options for Flop.Phoenix.table/1.

Generators

Generates a pagination element.

Generates a table with sortable columns.

Miscellaneous

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.

Converts a Flop struct into a keyword list that can be used as a query with Phoenix route helper functions.

Link to this section Types

Specs

pagination_option() ::
  {:current_link_attrs, keyword()}
  | {:ellipsis_attrs, keyword()}
  | {:ellipsis_content, Phoenix.HTML.safe() | binary()}
  | {:next_link_attrs, keyword()}
  | {:next_link_content, Phoenix.HTML.safe() | binary()}
  | {:page_links, :all | :hide | {:ellipsis, pos_integer()}}
  | {:pagination_link_aria_label, (pos_integer() -> binary())}
  | {:pagination_link_attrs, keyword()}
  | {:pagination_list_attrs, keyword()}
  | {:previous_link_attrs, keyword()}
  | {:previous_link_content, Phoenix.HTML.safe() | binary()}
  | {:wrapper_attrs, keyword()}

Defines the available options for Flop.Phoenix.pagination/1.

  • :current_link_attrs - The attributes for the link to the current page. Default: [class: "pagination-link is-current", aria: [current: "page"]].
  • :ellipsis_attrs - The attributes for the <span> that wraps the ellipsis. Default: [class: "pagination-ellipsis"].
  • :ellipsis_content - The content for the ellipsis element. Default: {:safe, "&hellip;"}.
  • :next_link_attrs - The attributes for the link to the next page. Default: [aria: [label: "Go to next page"], class: "pagination-next"].
  • :next_link_content - The content for the link to the next page. Default: "Next".
  • :page_links - Specifies how many page links should be rendered. Default: :all.
    • :all - Renders all page links.
    • {:ellipsis, n} - Renders n page links. Renders ellipsis elements if there are more pages than displayed.
    • :hide - Does not render any page links.
  • :pagination_link_aria_label - 1-arity function that takes a page number and returns an aria label for the corresponding page link. Default: &"Go to page #{&1}".
  • :pagination_link_attrs - The attributes for the pagination links. Default: [class: "pagination-link"].
  • :pagination_list_attrs - The attributes for the pagination list. Default: [class: "pagination-list"].
  • :previous_link_attrs - The attributes for the link to the previous page. Default: [aria: [label: "Go to previous page"], class: "pagination-previous"].
  • :previous_link_content - The content for the link to the previous page. Default: "Previous".
  • :wrappers_attrs - The attributes for the <nav> element that wraps the pagination links. Default: nil.

Specs

table_option() ::
  {:container, boolean()}
  | {:container_attrs, keyword()}
  | {:no_results_content, Phoenix.HTML.safe() | binary()}
  | {:symbol_asc, Phoenix.HTML.safe() | binary()}
  | {:symbol_attrs, keyword()}
  | {:symbol_desc, Phoenix.HTML.safe() | binary()}
  | {:table_attrs, keyword()}
  | {:tbody_td_attrs, keyword()}
  | {:tbody_tr_attrs, keyword()}
  | {:tfoot_td_attrs, keyword()}
  | {:tfoot_tr_attrs, keyword()}
  | {:th_wrapper_attrs, keyword()}
  | {:thead_th_attrs, keyword()}
  | {:thead_tr_attrs, keyword()}

Defines the available options for Flop.Phoenix.table/1.

  • :container - Wraps the table in a <div> if true. Default: false.
  • :container_attrs - The attributes for the table container. Default: [class: "table-container"].
  • :no_results_content - Any content that should be rendered if there are no results. Default: {:safe, [60, "p", [], 62, "No results.", 60, 47, "p", 62]}.
  • :table_attrs - The attributes for the <table> element. Default: [].
  • :th_wrapper_attrs - The attributes for the <span> element that wraps the header link and the order direction symbol. Default: [].
  • :symbol_asc - The symbol that is used to indicate that the column is sorted in ascending order. Default: "▴".
  • :symbol_attrs - The attributes for the <span> element that wraps the order direction indicator in the header columns. Default: [class: "order-direction"].
  • :symbol_desc - The symbol that is used to indicate that the column is sorted in ascending order. Default: "▾".
  • :tbody_td_attrs: Attributes to added to each <td> tag within the <tbody>. Default: [].
  • :tbody_tr_attrs: Attributes to added to each <tr> tag within the <tbody>. Default: [].
  • :tfoot_td_attrs: Attributes to added to each <td> tag within the <tfoot>. Default: [].
  • :tfoot_tr_attrs: Attributes to added to each <tr> tag within the <tfoot>. Default: [].
  • :thead_th_attrs: Attributes to added to each <th> tag within the <thead>. Default: [].
  • :thead_tr_attrs: Attributes to added to each <tr> tag within the <thead>. Default: [].

Link to this section Generators

Specs

pagination(map()) :: Phoenix.LiveView.Rendered.t()

Generates a pagination element.

Assigns

  • meta - The meta information of the query as returned by the Flop query functions.
  • path_helper - The path helper function that builds a path to the current page, e.g. &Routes.pet_path/3.
  • path_helper_args - The arguments to be passed to the route helper function, e.g. [@conn, :index]. The page number and page size will be added as query parameters.
  • for (optional) - The schema module deriving Flop.Schema. If set, Flop.Phoenix will remove default parameters from the query parameters.
  • event (optional) - If set, Flop.Phoenix will render links with a phx-click attribute.
  • target (optional) - Sets the phx-target attribute for the pagination links.
  • opts (optional) - Options to customize the pagination. See Flop.Phoenix.pagination_option/0. Note that the options passed to the function are deep merged into the default options. These options will likely be the same for all the tables in a project, so it probably makes sense to define them once in a function or set them in a wrapper function as described in the Customization section of the module documentation.

By default, page links for all pages are shown. You can limit the number of page links or disable them altogether by passing the :page_links option.

  • :all: Show all page links (default).
  • :hide: Don't show any page links. Only the previous/next links will be shown.
  • {:ellipsis, x}: Limits the number of page links. The first and last page are always displayed. The x refers to the number of additional page links to show.

For the page links, there is the :pagination_link_aria_label option to set the aria label. Since the page number is usually part of the aria label, you need to pass a function that takes the page number as an integer and returns the label as a string. The default is &"Goto page #{&1}".

By default, the previous and next links contain the texts Previous and Next. To change this, you can pass the :previous_link_content and :next_link_content options.

See the module documentation and Readme for examples.

Link to this function

table(assigns)

View Source (since 0.6.0)

Specs

Generates a table with sortable columns.

Assigns

  • headers - A list of header columns. Can be a list of strings (or safe HTML), or a list of {value, field_name} tuples.
  • items - The list of items to be displayed in rows. This is the result list returned by the query.
  • meta - The Flop.Meta struct returned by the query function.
  • path_helper - The Phoenix path or url helper that leads to the current page.
  • path_helper_args - The argument list for the path helper. For example, if you would call Routes.pet_path(@conn, :index) to generate the path for the current page, this would be [@conn, :index].
  • row_func - A function that takes one item of the items list and a keyword list with all additional assigns and returns the column values for that item's row.
  • row_opts (optional) - Keyword list that will be passed as the second parameter to the row_func.
  • for (optional) - The schema module deriving Flop.Schema. If set, header links are only added for fields that are defined as sortable and query parameters are hidden if they match the default order.
  • footer (optional) - A list of footer columns. Can be a list of strings or safe HTML.
  • event (optional) - If set, Flop.Phoenix will render links with a phx-click attribute.
  • target (optional) - Sets the phx-target attribute for the header links.
  • opts (optional) - Keyword list with additional options (see Flop.Phoenix.table_option/0). Note that the options passed to the function are deep merged into the default options. These options will likely be the same for all the tables in a project, so it probably makes sense to define them once in a function or set them in a wrapper function as described in the Customization section of the module documentation.

Table headers

Table headers need to be passed as a list. It is recommended to define a function in the View, LiveView or LiveComponent module that returns the table headers:

def table_headers do
  ["ID", {"Name", :name}, {"Age", :age}, ""]
end

This defines four header columns: One for the ID, which is not sortable, and columns for the name and the age, which are both sortable, and a fourth column without a header value. The last column will hold the links to the detail pages. The name and age column headers will be linked, so that they the order on the :name and :age field, respectively.

Table rows

You need to define a function that takes a single item from the list and a keyword list with any additional assigns. The function needs to return a list with one item for each column.

<Flop.Phoenix.sortable_table
  row_func={&table_row/2}
  row_opts={[socket: @socket]}
  ...
/>

def table_row(%Pet{id: id, name: name, age: age}, opts) do
  socket = Keyword.fetch!(opts, :socket)
  [id, name, age, link("show", to: Routes.pet_path(socket, :show, id))]
end

You can optionally pass a footer as a list of columns.

def table_footer(total) do
  ["", "Total: ", content_tag(:span, total, class: "total")]
end

<Flop.Phoenix.sortable_table
  ...
  footer={table_footer(@total)}
  ...
/>

See the module documentation and Readme for examples.

Link to this section Miscellaneous

Link to this function

build_path(path_helper, args, meta_or_flop_or_params, opts \\ [])

View Source (since 0.6.0)

Specs

build_path(function(), [any()], Flop.Meta.t() | Flop.t() | keyword(), keyword()) ::
  String.t()

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"
Link to this function

to_query(flop, opts \\ [])

View Source (since 0.6.0)

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]