maxmarcon / live_select Goto Github PK
View Code? Open in Web Editor NEWDynamic (multi)selection field for LiveView
Home Page: https://hex.pm/packages/live_select
License: Apache License 2.0
Dynamic (multi)selection field for LiveView
Home Page: https://hex.pm/packages/live_select
License: Apache License 2.0
While using the mode tag, after the user inserting anythin on the field and the tag being created, if you press enter on the blank field, it still considers as if the text is there and duplicate keep insert new tags every time you press enter.
If you are using style: :none
option and set both the :container_class
and :container_extra_class
(or any combination of _class and _extra_class) you get a match error at LiveSelect.Component.class/4
The following addition to the function resolves the error. I may be misunderstanding the usage, but happy to submit a PR if this looks right...
defp class(_style, _element, class_override, class_extend) do
class_override <> " #{class_extend}"
end
I decided to test live_select but ran into two issues.
This screenshot is from the demo app:
Any idea why this is overflowing? This happens on both Firefox and Chrome.
Most JS-based select dropdowns have some sort of bounds detection. This makes it such that if there is not enough space to show the dropdown below the input field, the dropdown opens upwards. Live_select doesn't appear to support this:
You can look at Headless-UI or shadcn/ui to get a sense of what I am talking about:
Thank you so much for making this open source! :)
Hi,
Thank you for building this.
Is there a possibility to add a No Data
message when the returned options is %{}
or []
? I'm happy to contribute if you can guide me to add this.
Encountered when running test:
git clone https://github.com/maxmarcon/live_select.git
cd live_select
mix deps.get
mix test
...
..11:54:52.833 [error] Task #PID<0.1379.0> started from #PID<0.1378.0> terminating
** (File.Error) could not stream "priv/static/assets/class.txt": no such file or directory
(elixir 1.14.0) lib/file/stream.ex:47: Collectable.File.Stream.into/1
(elixir 1.14.0) lib/enum.ex:1499: Enum.into_protocol/2
(elixir 1.14.0) lib/task/supervised.ex:89: Task.Supervised.invoke_mfa/2
(stdlib 4.0.1) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Function: #Function<6.25363132/0 in LiveSelectWeb.ShowcaseLive.spawn_save_classes_task/2>
Args: []
Did I miss out any steps?
This is a sample image / modal / dropdown that I want to display with live_select.
live_select has lots of 'keyboard' bindings and small things done right! I wish to support live_select with slots so that a custom slot can be passed for options / dropdown.
Would love you know your thoughts on this @maxmarcon .
Hello there!
We've been using your library lately and firstly we must say: THANK YOU! This is a hard problem and we were so glad to not start from scratch.
I wanted to run past you a little problem we're having to see what you think.
We are using live select in tags mode and using a list of genres that are stored in a separate database table. To start, we search the db for the first 10 genres alphabetically. Imagine a list of genres like Active, Adventure, Animation, etc. If I had previously selected something outside of the first 10 results, like the "War" genre, it will display the db id instead of the label. This happens because the options we passed to live select did not include "War", so when it attempted to find the value and retrieve the label, it was not found.
This list of options could potentially balloon to a huge list. We wouldn't want to pass all options to the live select component because a) we don't know how large this data set is and b) we don't want the popup list to be a massive list of options that goes off the screen.
Thoughts?
Now that phoenix_html has a 4.0 version, is it possible to update the dependency of live_select from 3.3 to 4.0?
In the demo, a change of the dark/light mode doesn't affect the color of the LiveSelect, which always stays white.
either the initial options should be restored or a possibility to detect the blur event so i can reset manually.
i'll make a minimal example if required. thought i'd pick your brain first.
If a field comes from the database, instead of showing the value from the label, it is showing from the value.
For example, when considering the map below:
%{label: "test", value: "1"}
In the search it would appear correctly as test
,
When the data is saved and reload using the data from the db it shows as 1
The dropdown search continues working as it should.
Save the record
Hi!
First of all, thanks a lot for your work, it's great!
I wanted to create a dynamic hierarchical LiveComponent wrapping LiveSelect. The problem I have is that when an option is selected, it's the Root LiveView (through the form's phx-change) who gets the even.
I tried wrapping the Heex in another form tag but that didn't work. I don't know if there is any other way of having more control over who gets the change event.
There might be an obvious way but I am new to LiveView, sorry.
Thanks in advance,
Rodrigo.
Hi,
Just linking the previous issue I opened so that the code samples and the context are available.
Issue is, the handle_info
function is triggered when the user inputs characters, but once an option is clicked, the phx_change
event is not triggered. Any idea why? Is this because I am using live_select
inside a component?
Also as mentioned in the other issues, live_select's handle_info
is received by the parent, so, I included the handle_event
also in the parent
so i tried live_select again and the dropdown does not close indeed.
phoenix 1.7, live_view 0.18, but my empty test project had the same stuff and no problem there.
i downloaded the lib and connected the local version to my app to debug.
it seems when it comes down to it the @hide_dropdown
variable is set correctly, but the display: none;
doesn't end up in the HTML.
Here's an image where i print the var out. this is with initial options only, no interaction.
another interesting thing i noticed was that the initial HTML coming from the server does in fact have style="display: none;"
included, but then the websocket gets two updates immediately and the second one has an empty class and style for this element. which is another confusing part, because the class does end up with appropriate classes so why doesn't style?
this is my thought process so far. i have no idea what it is in my app that is causing this. i thought perhaps you've got ideas where to look?
edit: i'm placing random values in places and it seems like none of the style attributes in the whole component get shown on page. not sure what this may or may not mean.
edit2: experimenting with raw style values it seems that it's not the LiveView websocket update that empties the style. so maybe javascript, but my project has barely any JS at all. new suspect: a library.
Hi,
I am executing
send_update(LiveSelect.Component, id: "workshop-tags", value: list_of_tags())
inside an update/2
callback of a live component, the live select updates correctly, but I got a
Uncaught TypeError: this.el.querySelector(...) is null
message, and the offending line is
live_select/assets/js/live_select.js
Line 82 in 30c9fab
This breaks my javascript script.
Am I doing something wrong?
Any idea how to solve?
Thank you
Hi there, thank you for creating this library!
I'm in a little tricky situation where I can't make use of tailwind
and daisyui
, so I have to handle styling based on the css my team uses, mainly bootstrap.
Without the usage of tailwind
or daisyui
, the X
icon on tags appears as a rectangle, like this:
(it looks the same even when style is set to :none
)
I have set bi bi-x
(https://icons.getbootstrap.com/icons/x/) to clear_button_class
, along with another custom class for background: transparent
and border-style: none
, which results in this:
This is what appears on inspect element of the x's
The svg
is present regardless of the bootstrap class and default styling (as it still appears with style={:none}
), it is an X when bi bi-x
is used, and as a rectangle when nothing is used.
Google tells me that duplicates tend to happen when either bootstrap-icons is installed with another icon library, or when <i class="bi bi-x"/>
is used instead of <i class="bi bi-x"></i>
. I checked our packages and we don't appear to have another icon library installed.
Workarounds that I have tried and failed:
content: ''
on bi::before
bi::before
, so it just resulted in the x disappearing entirely in both:tag
slot and hiding the clear button
I'm rather new to LiveView (I'm also primarily a backend dev, not frontend), so this could also just be that I didn't import/use the bootstrap icon properly. Otherwise, it may be due to an incompatibility of using it directly in a button
class?
Hopefully this makes sense!
Edit: I've found a workaround by making use of display: grid
, having the tag contents all be in 1 row, then setting display: flex
on the tag contents
Hi Max,
I added 200 ms delay in handle_params
so it is visible in the recording below.
The log is the same in both versions:
[debug] HANDLE EVENT "option_click" in LiveUIWeb.Admin.UserLive.Index
Component: LiveSelect.Component
Parameters: %{"idx" => "0"}
[debug] Replied in 118ยตs
[debug] HANDLE EVENT "users-update-filter" in LiveUIWeb.Admin.UserLive.Index
Parameters: %{"_target" => ["company_id"], "company_id" => "1", "company_id_text_input" => "ACME INC", "filters" => %{"0" => %{"field" => "company_id"}, "1" => %{"field" => "email", "op" => "ilike", "value" => ""}}}
[debug] Replied in 173ยตs
[debug] HANDLE PARAMS in LiveUIWeb.Admin.UserLive.Index
Parameters: %{"_target" => ["company_id"], "company_id" => "1", "company_id_text_input" => "ACME INC", "filters" => %{"0" => %{"field" => "company_id"}, "1" => %{"field" => "email", "op" => "ilike", "value" => ""}}}
[debug] QUERY OK source="users" db=0.3ms idle=1814.9ms
SELECT ...
[debug] QUERY OK source="users" db=0.2ms idle=1816.1ms
โณ Flop.meta/3, at: lib/flop.ex:929
[debug] Replied in 2ms
It is triggered when the updated stream is added to the socket:
socket |> stream(:items, items, reset: true)
Looks like the whole component is re-rendered:
Right now, the menu closes when a selection is made, and also when there's a mouse click outside anywhere on the screen.
We need two new options:
close_menu_after_selection
: Defaults to false. If true, the dropdown menu stays open after an option is selected.
Use case: You type something to filter the options, then want to select several from the filtered list in quick succession. Right now you have to do it one by one, which is very cumbersome.
persistent_menu
: Defaults to false. If true, the menu stays open and needs to be closed programmatically.
Use case: Right now there's no way to inspect the HTML markup of the dropdown field options, because the menu automatically closes when using the Inspect Element tool in Chrome. So we can't write tests for components that use LiveSelect!
Hi, this is a followup of the conversation in https://elixirforum.com/t/liveselect-dynamic-selection-input-component-for-liveview/49538/29?u=jaimeiniesta
The context is, I want to add a tagging editor, where the user can choose from previous tags but also add new ones, like here:
As mentioned in the Elixir Forum thread:
It would be something like a โdynamic option modeโ, where if you hit enter whatever you have typed will become a new selected option.
I have managed to make it more-or-less work, see video:
https://www.dropbox.com/s/a3ql5qs2zynggtj/live_select_2.mov?raw=1
But it won't work with the Enter key yet. What I did is:
<%= live_select f, :tag_search, mode: :tags, options: @live_select_options, placeholder: "Add tag" %>
and then listen to the ChangeMsg
to replace the options:
def handle_info(%LiveSelect.ChangeMsg{field: :tag_search, text: text}, socket) do
new_live_select_options = [text | socket.assigns.user_tags]
{:noreply, assign(socket, live_select_options: new_live_select_options)}
end
Where user_tags
is the original list of options from the existent user tags.
So for me what's left is being able to add new options with the "Enter" key, which should also clear the input field.
When displaying the search in a search result page where we landed by url I would like to be able to populate the value of the input using the parameters I have in url. I have not found any way to set a default value. There is the option to set a default vaule for the dropdown if the input is empty, but no way to have the input not empty
Is there a way I can populate the input value?
Thank you for this awesome library
Was wondering if there's chance to support setting all the default classes in config.exs
?
Something like this
config :live_select,
app: :some_app, #opitional: for specific umbrella app?
active_option_class: "text-white bg-red-800",
...
Thanks!
Hi all,
I have added deps/live_select/lib/live_select/component.*ex
to the content
array in my tailwind config file,
but the classes are not extracted correctly (I don't find them in the compiled css).
If I change a line to something like active_option: ~W(text-white "bg-gray-600"),
(note the quotes), tailwind extracts the class correctly.
This seems an upstream bug, but before I would like to make sure it's not only a problem of my setup.
Thank you
I have a usecase for options to contain more than a text value. I want to be able to display an html I creating with label and sublabel.
I was able to display my own html sending the options like this:
s = """
<span>
#{city}</br>
<small>#{state}</small>
</span>
"""
{raw(s), city}
but there is a problem when selecting the option from dropdown. It tries to serialize the label as json and I get a crash:
[error] GenServer #PID<0.1414.0> terminating
** (Protocol.UndefinedError) protocol Jason.Encoder not implemented for {:safe, "<span>\n Iaลi</br>\n <small>Iaลi</small>\n</span>\n"} of type Tuple, Jason.Encoder protocol must always be explicitly implemented. This protocol is implemented for the following type(s): Any, Atom, BitString, Date, DateTime, Decimal, Ecto.Association.NotLoaded, Ecto.Schema.Metadata, Float, Integer, Jason.Fragment, Jason.OrderedObject, List, Map, NaiveDateTime, Recenza.Models.Service, Recenza.Models.Speciality, Time
(jason 1.4.1) lib/jason.ex:213: Jason.encode_to_iodata!/2
First of all thanks for this very nice piece of software! It's filling a gap that I previously tried to work around using Select2 and some custom code. I highly appreciate the effort you put into this project. When trying it out in a pet project of mine I found a potential bug:
To reproduce I've set up a minimal example app at: https://github.com/cblock/live_select_sample using Phoenix 1.7.0-rc.0. Then I added live_select 0.3.2 as per documentation.
For demonstration puposes let's assume that I want to use live_select to choose a person's location.
I implemented the handle_info
callback in the live_component itself (not its parent liveviews which would be PersonLive.Index or PersonLive.Show respectievely depending on whether a user trigger's the form from the index or show view).
When I start the server, I see the following log output:
[debug] HANDLE EVENT
Component: LiveSelect.Component
View: LiveSelectSampleWeb.PersonLive.Index
Event: "keyup"
Parameters: %{"key" => "Control", "value" => "test"}
[debug] Replied in 146ยตs
[debug] warning: undefined handle_info in LiveSelectSampleWeb.PersonLive.Index. Unhandled message: %LiveSelect.ChangeMsg{id: "person_location_component", field: :location, text: "test", module: LiveSelect.Component}
[debug] HANDLE EVENT
Component: LiveSelect.Component
View: LiveSelectSampleWeb.PersonLive.Index
Event: "blur"
Parameters: %{"value" => "test"}
[debug] Replied in 49ยตs
To my understanding, live_select does not take into account the form's phx-target
attribute. Instead it always sends messages to the live_component's parent live view.
IMHO this behavior is not desirable as it leads to code duplication: I'd have to implement callbacks both within Index and Show LiveView.
It would be great if the support for multiple selected items is added. When enabled, the input field would display either N items selected
if more than 1 is selected, or work like it does now, and the selected items would have a checkbox next to them that would change state on click.
Maybe some ideas could be taken from:
cannot convert component LiveSelect.Component with id "test[review][0][name_review]_assignee_component" to HTML.
A component must always be returned directly as part of a LiveView template.
Any idea?
Hi,
I just want to understand how @hide_dropdown
is going to work when there are multiple live_select
on a single page? For example, when multi_select
is defined inside an inputs_for
I see in the code, you use the @hide_dropdown
variable for this, but when there are more than one live_select
, how does this work?
I'm trying to add a different CSS style for the selected options, so in the dropdown the cursor is changed to "none", but I can't see how to do this. This is my current setup:
<%= live_select f,
:tags,
mode: :tags,
options: @live_select_options,
update_min_len: 1,
placeholder: "Add tag",
style: :none,
container_class: "tag_editor_container",
text_input_class: "tag_editor_text_input",
dropdown_class: "tag_editor_dropdown",
option_class: "tag_editor_option",
active_option_class: "tag_editor_active_option",
selected_option_class: "tag_editor_selected_option" %>
@layer components {
.tag_editor_container {
@apply border my-4 p-4 rounded-md bg-gray-100;
}
.tag_editor_text_input {
@apply bg-gray-100 text-gray-900;
}
.tag_editor_text_input:focus {
@apply outline-none;
}
.tag_editor_dropdown {
@apply pt-4 pb-2 space-y-2;
}
.tag_editor_option {
@apply cursor-pointer;
}
.tag_editor_option:hover {
@apply font-bold text-blue-800;
}
.tag_editor_active_option {
@apply font-bold text-blue-800;
}
.tag_editor_selected_option {
@apply font-normal text-gray-500 cursor-default;
}
}
I want to make it clearer that the options that have been already selected are no longer clickable, so that's why I'd like to avoid a pointer cursor in them.
Maybe we could have an "available_option" class, as the opposite and complementary class to "selected_option"? This way we could style the options depending on that condition, available or already selected.
Right now, in order to select multiple options from the dropdown menu, you need to:
This is not good UX. The dropdown menu should open when the input field receives a click event.
Per the docs, the :selected_option_class
attr is only available when in :tags
mode. However, I believe being able to style the current selection uniquely is valuable even in :single
mode.
This is in fact how chrome's built-in select works (notice the check next to female
, indicating that is the current selection):
If you're open to this change, I'd be happy to PR it. Just don't want work to go to waste.
First off I would like to say great job on the library, it is extremally useful.
I had a question around testing when being used within a LiveView component. While the directive of phx-target={@myself}
works on the actual <.live_select />
element when being used in the live environment, when running this in a test environment the event messages are sent to the parent LiveView.
I in no way think this is a short coming of the library in anyway and understand this is something that still needs to be fleshed out in LiveView testing methodologies but was wondering if anyone has come up with a clever solution for this or if at the moment most are just not testing the live_select
component in their views and are instead direct testing their components.
as an example:
Component:
defmodule MyAppWeb.PageLive.FormComponent do
use MyAppWeb, :live_component
def render(assigns) do
~H"""
<.simple_form for={@form} id="page-form" phx-target={@myself} phx-change="validate" phx-submit="save">
<.input field={@form[:name]} type="text" label="Name" />
<.live_select field={@form[:cities]} phx-target={@myself} placeholder="Search Cities..." mode={:tags} />
<:actions>
<.button phx-disable-with="Saving...">Save Cities</.button>
</:actions>
<./simple_form>
"""
end
...
@impl true
def handle_event("live_select_change", %{"field" => "cities_tags", "text" => text, "id" => live_select_id}, socket) do
...
send_update(LiveSelect.Component, id: live_select_id, options: result)
{:noreply, socket}
end
end
Test:
... include the helper (with a few minor modifications to selectors) from this lib since it makes life much easier
test "can save cities", %{conn: conn} do
{:ok, new_live, _html} = live(conn, ~p"/cities/new")
type(new_live, "ala",
component: "#cities_live_select_component",
field: "cities_tags"
)
select_nth_option(new_live, 1,
method: :key,
component: "#cities_live_select_component"
)
assert new_live
|> form("#page-form",
cause: %{
"name" => "A Fake Title Name"
}
)
|> render_submit()
end
This results in the following error which you won't get in when using this from the browser:
Assume MyAppWeb.PageLive is the LiveView which is hosting this in modal or something similar.
** (UndefinedFunctionError) function MyAppWeb.PageLive.handle_event/3 is undefined or private
If anyone has any ideas on how to test in the scenario or any pointers it would be very much appreciated.
I upgraded to live_select 1.0.4 and LV 0.19 and suddenly many tests are failing for me.
I think this is related to live_select but I could be very much wrong (don't see live_select files in the stacktrace...)
Maybe you have an idea.
Here's one of the failing tests:
test "Adds an url", %{conn: conn, workshop: workshop} do
{:ok, view, _} = live(conn, "/admin/workshops/#{workshop.id}/edit")
x =
view
|> element("[phx-click='add-url']")
|> render_click()
|> assert_html("#workshop_urls_2_url", name: "workshop[urls][2][url]")
end
Here's the stacktrace, please note the error message is involving a live_select element:
1) test Adds an url (ZdbWeb.Live.Workshops.UpdateTest)
test/zdb_web/live/workshops/update_test.exs:198
** (EXIT from #PID<0.1082.0>) an exception was raised:
** (CaseClauseError) no case clause matching: [["select", %{id: "workshop-hallmarks", input_event: true, mode: :tags, selection: [%{key: "Steel Computer", label: "Steel Computer", value: "077388da-33bc-4653-9dfc-89bf88de460f"}, %{key: "Practical Granite Shoes", label: "Practical Granite Shoes", value: "0227eed3-6a50-4b7d-8137-812293aeb8fc"}, %{key: "Cotton Pants", label: "Cotton Pants", value: "7eb1fdcd-a7d8-4976-b831-2acdd4f7ab67"}]}], ["select", %{id: "workshop-tags", input_event: true, mode: :tags, selection: [%{key: "Small Concrete Computer", label: "Small Concrete Computer", value: "13a73bdc-08e7-49fb-b8c1-113129408ccf"}, %{key: "Fantastic Wooden Shirt", label: "Fantastic Wooden Shirt", value: "70a48d13-880d-4f76-86b7-de7c3c423ac4"}]}]]
(phoenix_live_view 0.19.1) lib/phoenix_live_view/test/dom.ex:234: Phoenix.LiveViewTest.DOM.find_component/5
(phoenix_live_view 0.19.1) lib/phoenix_live_view/test/dom.ex:211: anonymous fn/4 in Phoenix.LiveViewTest.DOM.merge_diff/2
(stdlib 4.0.1) maps.erl:411: :maps.fold_1/3
(phoenix_live_view 0.19.1) lib/phoenix_live_view/test/dom.ex:210: Phoenix.LiveViewTest.DOM.merge_diff/2
(phoenix_live_view 0.19.1) lib/phoenix_live_view/test/client_proxy.ex:732: Phoenix.LiveViewTest.ClientProxy.merge_rendered/3
(phoenix_live_view 0.19.1) lib/phoenix_live_view/test/client_proxy.ex:828: Phoenix.LiveViewTest.ClientProxy.handle_reply/2
(phoenix_live_view 0.19.1) lib/phoenix_live_view/test/client_proxy.ex:452: Phoenix.LiveViewTest.ClientProxy.handle_info/2
(stdlib 4.0.1) gen_server.erl:1120: :gen_server.try_dispatch/4
(stdlib 4.0.1) gen_server.erl:1197: :gen_server.handle_msg/6
(stdlib 4.0.1) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
I would like to be able to restore selections that hadn't been submitted yet, or that encountered an error on submission, like other forms seem to do via their changesets.
For example, I have a tabbed interface where switching tabs switches what info and form you're looking at. This live select is the only one that loses your work if you click away (within the same liveview) without saving.
It may be possible to simply take the current value from the form data using Phoenix.HTML.Form.input_value/2 in the template.
I'm having trouble getting selections to work, and I've traced it to the blur event:
def handle_event("blur", _params, socket) do
{:noreply, assign(socket, :hide_dropdown, true)}
end
For me, when I click on the option, the blur
event fires, but the option_click
and whatever is set on the form's phx-change
never do. If I remove the :hide_dropdown
assign, the option_click
fires, and the form's change event happens.
I'm not entirely sure why it's blurring when I click an option, but it happens even if I use a live select with a minimal layout template and remove some other libraries from our app.js, so I don't think it's our own JS interfering.
I think this is probably a race condition where, if blur is processed before option click, the liveview updates with the hidden dropdown and drops the click event. Perhaps something could be done with send_update_after/4?
(Side note: I'm not sure the component template's phx_change: "change"
on the text input itself goes anywhere.)
I'm thinking about what to do for a workaround in the meantime. This library seems very helpful to make a liveview-friendly select2 equivalent!
with LiveView set to 0.19, i get this error.
Because the lock depends on live_select 1.0.0 which depends on phoenix_live_view ~> 0.18.4, the lock requires phoenix_live_view ~> 0.18.4.
And because your app depends on the lock, phoenix_live_view ~> 0.18.4 is required.
So, because your app depends on phoenix_live_view ~> 0.19.0, version solving failed.
** (Mix) Hex dependency resolution failed
Is it possible to have an attribute in the component to limit the number of displayed results if there are too many?
i.e. like the 'limit' attribute
<%= live_select(f, :selected_countries,
mode: :tags,
placeholder: "Type to select countries",
limit: 10
)
%>
Because one of the issues, except the aesthetic one is that the layout of the page is distorted if the selection list gets too big, by adding vertical scrollbars.
Hello!
With the update of LiveView 0.20.4
, live_select seems to no longer work.
When clicking on the input there is this error in the console:
Uncaught TypeError: form is null
When I downgrade LiveView to 0.20.3
, it's working.
Hello and thanks for this project!
Setting options on initialization like
<.live_select :if={ @worksite.id != nil }
field={@form[:project_id]}
options={ [ {@worksite.project.name,@worksite.project.id} ] }
phx-target={@myself} />
initially fills the select and works as expected but any change to other form fields (also LiveSelect) causes a "validate" and the component resets its displayed value to the .id part of the tuple. If selected it displays the .label part again. There are only LiveSelects in the form 1-3 of them and all reset to the .id.
I am new to Phoenix and LiveView hence the possible in the title. I made a demo with LiveSelect last week (1.2.2) and it worked as expected but after integration (now 1.3) it started to exhibit this strange behavior.
Any advice is welcome, thanks again.
Currently, I can't see a good way to tell the component to clear its selected options in :tags
mode. This is useful when you save the form via liveview and want to allow the user to make further selections without refreshing the page. If I'm just missing something, please let me know!
Perhaps allowing send_update/3
to change the :selection
assign would be enough, or maybe it could listen for an event that triggers reset/1
. I'd be willing to throw together a PR to that effect.
My current workaround is pushing an event on save from the liveview that uses the component, then listening for it via JavaScript and simulating clicks to remove the selected options. (Compare https://hexdocs.pm/phoenix_live_view/js-interop.html#handling-server-pushed-events .)
<script>
window.addEventListener('phx:reset-my-form', (e) => {
let nodes = document.querySelectorAll("#my-form [phx-click='option_remove']");
// start from last, otherwise we only end up clearing the early ones
for (let i = nodes.length - 1; i >= 0; i--) {
nodes[i].dispatchEvent(new MouseEvent('click', {bubbles: true, view: window}));
}
})
</script>
This seems to be working fine, but it feels a bit hacky, so a nicer way to do this in the future would be cool.
@maxmarcon loving what you've started here! is there a known way to get the selected options to appear inside the search input, as shown in the gif above:
Originally posted by @rxndxm in #11 (comment)
once the user selects a value it should not disappear, only change to a new value if user selects it.
i made a repo where this exists built on top of Phoenix 1.7 RC2 and it's LiveView generators.
If you have two live selects in the same form, selecting a value for one updates both.
The form is set up as follows:
<.form for={:unit_converter_form} let={f} phx-change="change" phx-submit="submit" class="w-1/2">
<div class="flex gap-2 items-center">
<%= LiveSelect.live_select(f, :unit_from, add_placeholder("Units From", @live_select_opts)) %>
<%= LiveSelect.live_select(f, :unit_to, add_placeholder("Units To", @live_select_opts)) %>
</div>
<%= submit("Submit", class: "btn btn-primary") %>
</.form>
It appears to be due to the js handleEvents firing for both instances. On my local copy I made a couple of changes to resolve this. I don't know if I am misunderstanding how to use multiple instances, but if these changes make sense, I'm happy to package them into a PR.
I patched the mounted
in live_select.js to look like this:
mounted() {
this.handleEvent("reset", ({ id: id }) => {
if (this.el.id == id) { // Note check on matching DOM id
this.setSearchInputValue("")
this.setHiddenInputValue("")
}
})
this.handleEvent("selected", ({ selected: [label, selected], id: id }) => {
if (this.el.id == id) {
this.setSearchInputValue(label);
this.setHiddenInputValue(selected)
}
})
this.attachDomEventHandlers()
},
and the functions that invoke the events in component.ex to look like this:
defp select(socket, selected_position) do
{label, selected} = Enum.at(socket.assigns.options, selected_position)
id = socket.assigns.id # Pass in DOM id
socket
|> assign(
options: [],
current_focus: -1,
search_term: label,
selected: selected
)
|> push_event("selected", %{selected: [label, selected], id: id})
end
defp reset_input(socket) do
id = socket.assigns.id
socket
|> assign(options: [], selected: nil, search_term: "")
|> push_event("reset", %{id: id})
end
This is more like a question but I wasn't able to get live_select
input working in a form where the inputs are inside inputs_for
block rather than top level of the form. I can't exclude that I did something incorrectly but the live_select_change
event handling function was never called. If you could be so kind as to let me know whether this type of use case is fully supported and should work?
If there is a lot of options for the select, it would be very helpful to be able to lazy load when user scrolls through the dropdown. Is it currently implementable?
Hi, as a followup to #11, it would be great to enter several tags by the use of the comma (,
) character, as in this example:
https://codepen.io/atomgiant/pen/QWjWgKz
That is if you type tag1,tag2,tag3
you end up with 3 independent tags: tag1
, tag2
and tag3
.
How could we achieve this behavior?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.