kevinschweikert
Hi together,
i want to build a filter UI where the user can select some items with a checkbox and then the results get filtered based on the selected checkboxes. For example, a use case where we have some categories in a DB and give the user a checkbox for each category to filter for. So far so good and i had no problem implementing that.
But i want to have another checkbox which lets the user select all the categories at once or deselect every category at once. Additionally, the behaviour should be, that when a user deselects one category while the select all box is checked it should become unchecked and vice versa, when the user selects every category by hand, the select all checkbox should be checked as well.
My first step was to define a schema for the form which looks something like this:
defp parse_filter(default_filter, attrs \\ %{}) do
fields = %{
all: :boolean,
selected: {:array, :integer}
}
{default_filter, fields}
|> Ecto.Changeset.cast(attrs, Map.keys(fields))
|> Map.put(:action, :validate)
end
Is store the filter params in the URL with:
def handle_event("change-categories", %{"categories" => params}, socket) do
form = parse_filter(socket.assigns.filter, params)
filter = apply_filter(form)
{:noreply, socket |> push_patch(to: ~p"/?#{filter}")}
end
def handle_params(params, _, socket) do
form = parse_filter(socket.assigns.filter, params)
filter = apply_filter(form)
{:noreply,
socket
|> assign(
filter: filter,
filtered_categories: filter_categories(socket.assigns.categories, filter)
)
|> assign_form(form)}
end
I’ve tried with some Ecto.Changeset.get_change/put_change in the validation with parse_filter/2 but all and selected would overwrite each other.
I’ve prepared a gist with my idea, but i can’t figure out if i am on the right track with my plan. Does anybody have a solution for this problem or can point me in the right direction?
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #blog-post
- #elixir-ls
- #elixirconf-us
- #ai
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming











Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
Joep
Have you seen Add bulk actions in Phoenix LiveView · FullstackPhoenix ?
greven
Here’s a snippet of what I have done in a multi-step form some years ago. Probably there is a more elegant solution for this, but this was done “in a rush” about 4 years ago, anyway, it might help you.
The amount of possible options here was like 4 and static, maybe if you have dynamic options it might not work that well with this approach.
kevinschweikert
Ah thank you! I have seen it and it would be a solution for the problem, but i would really like a form based solution, so i can use this filter in combination with some more filter options which are already working in a form. But if i can’t figure out a solution i will definitely use this!
sa-mm
This might get you part of the way there or at least give you some ideas about where you want to go:
I’m not entirely sure what you mean by “form based solution,” so maybe referencing the
categoriesandfiltered_categoriesassigns isn’t acceptable, and deselecting the Select All doesn’t work because the browser doesn’t want to give up focus (I think).One thing that looks like it might cause trouble is that you’re reading the previous filters off the assigns when you call parse_filter. Maybe you want just one source of truth for the filters, which you’ll get from handle_params.
cmo
You can use a checkbox for the Select All input and handle the toggling of that in a hook. This method does not require network trips for selecting/deselecting and will return to the original selection when cancel is clicked, or the dropdown is closed. There is a
JS.dispatch("cancel")on the close trigger.The Hook:
The component takes a list of options of the form
%{id: 1, value: "Some Value", available: true/false, selected: true/false}LostKobrakai
You weren’t far off: Revisions · Phoenix LiveView filter toogle all problem · GitHub
Needed a bit working around the fact that empty lists cannot be represented in url encoding.
kevinschweikert
Thank you @LostKobrakai! I was so close in my attempts to solve this. I wrote some kind of
adjust_by_latest_changes/2function, but i didn’t think about handling the third case when there are no changes inall.I had to change the solution with the empty list params to something like this, to prevent overriding my preselected categories in
handle_params.and in
handle_paramsprovide some default params with:And finally i had to remove the line
|> Ecto.Changeset.change(selected: [])because it is already handled in the params workaround. Or is there a better way to do this?I will update my gist with these changes. Thank you all for your time and ideas! I’m very thankful for your help!
LostKobrakai
What does “preselected” mean exactly? I’d suggest modeling that instead of changing how you deal with params everywhere.
kevinschweikert
It’s not clear from my gist but in the application i get the categories from the DB and they have a boolean field
preselected. That’s whats basically happening inon_mountwhen we set the first filter withAnd i want to have (in this example) the category with the ID == 0 already selected. But on the first visit from the user there are no params set so it will override the filter in
handle_paramswith an empty list when we use|> Ecto.Changeset.change(selected: [])LostKobrakai
So
handle_paramsbeing called the first time is “special”. I’d have an assignpreselected, which you fill in mount, in handle_params you adjust the result ofparse_filterwith allpreselectedcategories and at the end of handle_params you setpreselected: []to essentially disable preselection going forward.