flop
flop copied to clipboard
[Question] - Dynamic Ops
Summary
Hey Woylie,
Sorry for opening a ticket - I'm trying to create some dynamic ops & looking for advice.
I'm trying to achieve something like this
Where I have certain filters, I can further drill down.
What I have implemented works with bad / non updating elements.
I have my filter_forms
<Flop.Phoenix.filter_fields :let={i} form={f} fields={@fields}>
<select
...
phx-change="numeric-filter"
>
<option
:for={{key, label} <- [{"equal", "Is equal to"}, {"less_than", "Is less than"}]}
value={"#{key}"}
selected={@field.field.form.data.op == a}
>
<%= label %>
</option>
</select>
<input
id={"#{@field.field.id}_desktop"}
name={@field.field.name}
type="number"
value={@field.field.value}
field={{@field.field.form, @field.field.field}}
{@field.rest}
/>
<./Flop.Phoenix.filter_fields>
Then my liveview I've the following/combo
- Keep params in assigns & update it as 'numeric-filter' is fired
- this works to an extent but the input "#{@field.field.id}_desktop" loses it's values when switching types
- When initializing filter_forms, have a nurmic-filter for ops in assigns, that changes value as required
- has similiar issues to above
Any guidance would be great thanks :)
Steps to reproduce
- ...
Expected behaviour
No response
Actual behaviour
No response
Elixir/Erlang version
1.15.6
Flop and Ecto versions
- ecto 3.10.3 (Hex package) (mix)
- ecto_sql 3.10.2 (Hex package) (mix) locked at 3.10.2 (ecto_sql) 68c018de
- flop 0.23.0 (Hex package) (mix) locked at 0.23.0 (flop) 0521d0cb
- flop_phoenix 0.22.2 (Hex package) (mix) locked at 0.22.2 (flop_phoenix) 8aa7e493
Additional context
No response
Summary
Hey Woylie,
Sorry for opening a ticket - I'm trying to create some dynamic ops & looking for advice.
I'm trying to achieve something like this
Where I have certain filters, I can further drill down.
What I have implemented works with bad / non updating elements.
I have my filter_forms
<Flop.Phoenix.filter_fields :let={i} form={f} fields={@fields}> <select ... phx-change="numeric-filter" > <option :for={{key, label} <- [{"equal", "Is equal to"}, {"less_than", "Is less than"}]} value={"#{key}"} selected={@field.field.form.data.op == a} > <%= label %> </option> </select> <input id={"#{@field.field.id}_desktop"} name={@field.field.name} type="number" value={@field.field.value} field={{@field.field.form, @field.field.field}} {@field.rest} /> <./Flop.Phoenix.filter_fields>
I haven't implemented something like that yet. I played it bit right now, and I came this far:
<Flop.Phoenix.filter_fields :let={i} form={@form} fields={@fields} dynamic={true}>
<.input
label={i.label}
type={i.type}
field={i.field}
{i.rest}
/>
<.input
label="Operator"
type="select"
field={Map.update!(i.field.form[:op], :id, &"#{&1}_override")}
options={[{"equals", :==}, {"less than", :<}, {"greater than", :>}]}
/>
</Flop.Phoenix.filter_fields>
filter_fields/1
renders a hidden input for the operator. Here, a select is used to override that hidden input. The field struct derived from the form in the field struct for the value input. I appended override
to the field id to prevent duplicate DOM IDs. I also added the dynamic={true}
option.
This works until you type something in the text input. For some reason, the operator select resets in that case, although the parameters and the meta struct look fine.
I didn't have to implement a dynamic filter form yet, and I don't know what's going wrong here yet. I was planning to implement a demo application at some point, which would also include dynamic operators in filter forms, and completely dynamic forms. But I don't know when I'll get to that.
Thanks @woylie for the example & insight. I'll have a play with the everything see if I can come up with anything that works, work arounds or solutions :)
Great news @woylie I got it to work with what doesn't seem to much of a hack.
With my components and such the code is below - you fire a handle event in the form of all the events that the form fires off.
All you need to do is take the field name which looks something like filter[filters][2][value]
and change it to modify the op
value. So we need to fire the filter[filters][2][op]
and the value associated along with that will change the handle events nicely.
everything updates on page, nothing is disappearing for me. No need to muck around with assigns, or firing events to other components etc. Seems like a very simple nice solution - at the moment. Thanks for taking the time to point me in the right direction. Also I could leave dynamic={true} out of the equation.
<.input label={@field.label} type={@field.type} field={{@field.field.form, @field.field.field}} {@field.rest} />
<.input
id={Map.update!(@field.field.form, :id, &"#{&1}_override").id}
name={String.replace(@field.field.name, "[value]", "[op]")} <!-- Important part here ! -->
label="Operator"
type="select"
errors={[]}
>
<:options
:for={{key, label} <- [{"equals", :==}, {"less than", :<}, {"greater than", :>}]}
id={"#{key}_option_#{@field.label}_desktop"}
value={"#{label}"}
selected={false}
>
<%= label %>
</:options>
</.input>
Cheers!
Actually turns out there are some more issues with it.
What I have found is that @field.field.form.data
<- the data in here will only update correctly if the original ops
value associated with it is the same as originally passed in to the filter_form
fields.
A crude but doable work around for the moment is to reach into @field.field.form.source.flop.filters
and pull out the required values here. This only works to an extent - the 'op' selector can track this, but the main input will get wiped because it's still using the @field.field.form.data
field.
In short -> @field.field.form.data
updater should be checked to make sure the ops can be updated on a handle_event
I believe?
the data in here will only update correctly if the original ops value associated with it is the same as originally passed in to the filter_form fields.
That's true, that's the current implementation. I'll get to the functionality for more dynamic filter form eventually. I don't have any advice at this point, unfortunately.
All good - appreciate all the work so far on the lib :) it's great.