defmodule Backpex.Filters.Boolean do @moduledoc """ The boolean filter renders one checkbox per given option, hence multiple options can apply at the same time. Instead of implementing a `query` callback, you need to define predicates for each option leveraging [`Ecto.Query.dynamic/2`](https://hexdocs.pm/ecto/Ecto.Query.html#dynamic/2). > #### Warning {: .warning} > > Note that only query elements will work as a predicate that also work in an [`Ecto.Query.where/3`](https://hexdocs.pm/ecto/Ecto.Query.html#where/3). If none is selected, the filter does not change the query. If multiple options are selected they are logically reduced via `orWhere`. See the following example for an implementation of a boolean filter for a published field. defmodule MyAppWeb.Filters.EventPublished do use Backpex.Filters.Boolean @impl Backpex.Filter def label, do: "Published?" @impl Backpex.Filters.Boolean def options do [ %{ label: "Published", key: "published", predicate: dynamic([x], x.published) }, %{ label: "Not published", key: "not_published", predicate: dynamic([x], not x.published) } ] end end > #### `use Backpex.Filters.Boolean` {: .info} > > When you `use Backpex.Filters.Boolean`, the `Backpex.Filters.Boolean` module will set `@behavior Backpex.Filters.Boolean`. > In addition it will add a `render` and `render_form` function in order to display the corresponding filter. > It will also implement the `Backpex.Filter.query` function to define a boolean query. """ use BackpexWeb, :filter @doc """ The list of options for the select filter. """ @callback options :: [map()] defmacro __using__(_opts) do quote do use BackpexWeb, :filter use Backpex.Filter alias Backpex.Filters.Boolean, as: BooleanFilter @behaviour Backpex.Filters.Boolean @impl Backpex.Filter def query(query, attribute, value) do BooleanFilter.query(query, options(), attribute, value) end @impl Backpex.Filter def render(assigns) do assigns = assign(assigns, :options, options()) BooleanFilter.render(assigns) end @impl Backpex.Filter def render_form(assigns) do assigns = assign(assigns, :options, options()) BooleanFilter.render_form(assigns) end defoverridable query: 3, render: 1, render_form: 1 end end attr :value, :any, required: true attr :options, :list, required: true def render(assigns) do assigns = assign(assigns, :label, option_value_to_label(assigns.options, assigns.value)) ~H""" {@label} """ end attr :form, :any, required: true attr :field, :atom, required: true attr :value, :any, required: true attr :options, :list, required: true def render_form(assigns) do value = if is_nil(assigns.value), do: [], else: assigns.value options = Enum.map(assigns.options, fn %{label: l, key: k} -> {l, k} end) assigns = assigns |> assign(:value, value) |> assign(:options, options) ~H"""