Flop Phoenix - how to filter on all fields declared as filterable?

Hi, I’ve declared two fields as filterable in the schema.

Schema
//territory/country.ex
@derive {
    Flop.Schema,
    filterable: [:country_code, :country_name],
    sortable: [:country_id, :country_code, :country_name],
    default_limit: 10
  }

  schema "countries" do
    field :country_id, :integer
    field :country_code, :string
    field :country_name, :string
    field :iso3, :string
    timestamps(type: :utc_datetime)
  end

I’ve created a search function

Search Function
//territory.ex
def list_countries2(params) do
    # Convert search parameter to a query condition
    base_query = from c in Country

    query = case get_in(params, ["filters", "0", "value"]) do
      value when is_binary(value) and value != "" ->
        pattern = "%#{String.replace(value, ~r/[%_]/, "\\\\\\0")}%"
        from c in base_query,
          where: fragment("lower(?) LIKE lower(?) OR lower(?) LIKE lower(?)",
            c.country_name, ^pattern,
            c.country_code, ^pattern)
      _ ->
        base_query
    end

    Flop.validate_and_run(
      query,
      params,
      for: Country,
      default_limit: 5,
      default_order: [asc: :country_name]
    )
  end

I’ve created a filter_form

Search Function
attr :fields, :list, required: true
  attr :meta, Flop.Meta, required: true
  attr :id, :string, default: nil
  attr :on_change, :string, default: "update-filter"
  attr :target, :string, default: nil

  def filter_form(%{meta: meta} = assigns) do
    assigns = assign(assigns, form: Phoenix.Component.to_form(meta), meta: nil)

    ~H"""
    <.form
      for={@form}
      id={@id}
      phx-target={@target}
      phx-change={@on_change}
      phx-submit={@on_change}
    >
      <.filter_fields :let={i} form={@form} fields={@fields}>
        <.input
          field={i.field}
          type={i.type}
          phx-debounce={120}
          {i.rest}
        />
      </.filter_fields>
    </.form>
    """
  end

//flop_components.ex

I’ve added a search box to the component in the template

heex template
//index.html.heex
<.filter_form
    fields={[country_name: [op: :like, autofocus: true, type: "search", phx_debounce: "150", placeholder: "Search Country, Code..."]]}
    meta={@meta}
    id="country-filter-form"
  />

But…when I search, I can only search in the one field - country_name. If I add another filterable field country_code in the heex template, it adds entire another search box for that field.

I need to have one search box and to be able to search for all the fields that are declared in the Flop.Schema as filterable. How to do it? Thanks

image

All is sorted now. I had to use compound_fields and also add the new virtual field that would combine both fields to the list of filterable:

@derive {
    Flop.Schema,
    filterable: [:country_code, :country_name, :search],
    sortable: [:country_id, :country_code, :country_name],
    default_limit: 10,
    adapter_opts: [
      compound_fields: [
        search: [:country_code, :country_name]
      ]
    ]
  }

and I had to change my convoluted query into a simpler Flop’s query.

def list_countries2(params) do
    Flop.validate_and_run(
      Country,
      params,
      for: Country,
      default_limit: 5,
      default_order: [asc: :country_name]
    )
  end
1 Like