Flop Phoenix View Source
Flop Phoenix is an Elixir library for filtering, ordering and pagination with Ecto, Phoenix and Flop.
Installation
Add flop_phoenix
to your list of dependencies in the mix.exs
of your Phoenix
application.
def deps do
[
{:flop_phoenix, "~> 0.9.0"}
]
end
Follow the instructions in the Flop documentation to set up your business logic.
Fetch the data
Define a function that calls Flop.validate_and_run/3
to query the list of
pets.
defmodule MyApp.Pets do
alias MyApp.Pet
def list_pets(params) do
Flop.validate_and_run(Pet, params, for: Pet)
end
end
In your controller, pass the data and the Flop meta struct to your template.
defmodule MyAppWeb.PetController do
use MyAppWeb, :controller
alias MyApp.Pets
action_fallback MyAppWeb.FallbackController
def index(conn, params) do
with {:ok, {pets, meta}} <- Pets.list_pets(params) do
render(conn, "index.html", meta: meta, pets: pets)
end
end
end
You can fetch the data similarly in the handle_params/3
function of a
LiveView
or the update/2
function of a LiveComponent
.
defmodule MyAppWeb.PetLive.Index do
use MyAppWeb, :live_view
alias MyApp.Pets
@impl Phoenix.LiveView
def handle_params(params, _, socket) do
with {:ok, {pets, meta}} <- Pets.list_pets(params) do
{:noreply, assign(socket, %{pets: pets, meta: meta})}
end
end
end
HEEx templates
In your template, add a sortable table and pagination links.
<h1>Pets</h1>
<Flop.Phoenix.table
items={@pets}
meta={@meta}
path_helper={&Routes.pet_path/3}
path_helper_args={[@socket, :index]}
headers={[{"Name", :name}, {"Age", :age}]}
row_func={fn pet, _opts -> [pet.name, pet.age] end},
opts={[for: MyApp.Pet]}
/>
<Flop.Phoenix.pagination
meta={@meta},
path_helper={&Routes.pet_path/3},
path_helper_args{[@socket, :index]},
opts={[for: MyApp.Pet]}
/>
path_helper
should reference the path helper function that builds a path to
the current page. path_helper_args
is the argument list that will be passed to
the function. If you want to add a path parameter, you can do it like this.
<Flop.Phoenix.pagination
meta={@meta},
path_helper={&Routes.pet_path/4},
path_helper_args{[@conn, :index, @owner]},
opts={[for: MyApp.Pet]}
/>
If the last argument is a keyword list of query parameters, the query parameters for pagination and sorting will be merged into that list.
The for
option allows Flop Phoenix to determine which table columns are
sortable. It also allows it to hide the order
and page_size
parameters if they match the default values defined with Flop.Schema
.
EEx templates
In EEX templates, you will need to call the functions directly and pass a map
with the assigns. You need to include __changed__: nil
in the map. Do not call
the functions like this within a LiveView, since it will prevent the components
from being updated.
<h1>Pets</h1>
<%= table(%{
__changed__: nil,
items: @pets,
meta: @meta,
path_helper: &Routes.pet_path/3,
path_helper_args: [@conn, :index],
headers: [{"Name", :name}, {"Age", :age}],
row_func: fn pet, _opts -> [pet.name, pet.age] end,
opts: [for: MyApp.Pet]
})
%>
<%= pagination(%{
__changed__: nil,
meta: @meta,
path_helper: &Routes.pet_path/3,
path_helper_args: [@conn, :index],
opts: [for: MyApp.Pet]
})
%>
Clean up the template
To keep your templates clean, it is recommended to define a table_headers/1
and table_row/2
function in your View
, LiveView
or LiveComponent
module.
The opts
are passed as a second argument to the row_func
, so you can add any
additional parameters you need.
The LiveView module:
defmodule MyAppWeb.PetLive.Index do
use MyAppWeb, :live_view
alias MyApp.Pet
alias MyApp.Pets
@impl Phoenix.LiveView
def handle_params(params, _, socket) do
with {:ok, {pets, meta}} <- Pets.list_pets(params) do
{:noreply, assign(socket, %{pets: pets, meta: meta})}
end
end
def table_headers do
[
# {display value, schema field}
{"Name", :name},
{"Age", :age},
""
]
end
def table_row(%Pet{} = pet, opts) do
socket = Keyword.fetch!(opts, :socket)
[
pet.name,
pet.age,
link "show", to: Routes.pet_path(socket, :show, pet)
]
end
end
The template:
<Flop.Phoenix.table
items={@pets}
meta={@meta}
path_helper={&Routes.pet_path/3}
path_helper_args={[@socket, :index]}
headers={table_headers()}
row_func={&table_row/2},
opts={[for: MyApp.Pet, socket: @socket]}
/>
Refer to the Flop.Phoenix
module documentation for more examples.