Last active
August 24, 2020 11:51
-
-
Save jamiedumont/13a803895726cb58141148f82afc65e3 to your computer and use it in GitHub Desktop.
"Typeahead" style autocomplete in LiveView form
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule RecordWeb.CompositeComponent do | |
use RecordWeb, :live_component | |
alias Record.Movements | |
alias Record.Core.Composite | |
import Ecto.Changeset | |
def update(assigns, socket) do | |
movement = case input_value(assigns.composite_form, :movement_id) do | |
nil -> nil | |
movement_id -> Movements.get_movement!(movement_id) | |
end | |
{:ok, | |
socket | |
|> assign(assigns) | |
|> assign(:movement, movement) | |
} | |
end | |
def render(assigns) do | |
RecordWeb.WorkoutView.render("define_composite.html", assigns) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div> | |
<h2>New Composite</h2> | |
<%= hidden_input @composite_form, :uuid %> | |
<%= if is_nil(@movement) do %> | |
<div> | |
<label>Search movement</label> | |
<%= text_input @el_form, :movement_query, list: "results" %> | |
<div> | |
<h3>Search results</h3> | |
<%= for m <- @movement_results do %> | |
<button | |
type="button" | |
phx-target="#element_definition" | |
phx-click="add-movement" | |
phx-value-composite-id="<%= input_value(@composite_form, :uuid) %>" | |
phx-value-movement-id="<%= m.id %>" | |
><%= m.name %></button> | |
<% end %> | |
</div> | |
</div> | |
<% end %> | |
<%= if !is_nil(@movement) do %> | |
<%= hidden_input @composite_form, :movement_id %> | |
<% primary_units = Enum.filter(@movement.movement_units, fn m -> m.type == "primary" end) %> | |
<% secondary_units = Enum.filter(@movement.movement_units, fn m -> m.type == "secondary" end) %> | |
<% tertiary_units = Enum.filter(@movement.movement_units, fn m -> m.type == "tertiary" end) %> | |
<div> | |
<% movement_id = input_value(@composite_form, :movement_id) %> | |
<%= number_input @composite_form, :primary_quantity %> | |
<%= select @composite_form, :primary_unit, Enum.map(primary_units, &{&1.unit.name, &1.unit.id}) %> | |
<span><%= @movement.name %></span> | |
<%= if !Enum.empty?(secondary_units) do %> | |
<span> @ </span> | |
<%= number_input @composite_form, :secondary_quantity %> | |
<%= select @composite_form, :secondary_unit, Enum.map(secondary_units, &{&1.unit.name, &1.unit.id}) %> | |
<% end %> | |
<%= if !Enum.empty?(tertiary_units) do %> | |
<span> & </span> | |
<%= number_input @composite_form, :tertiary_quantity %> | |
<%= select @composite_form, :tertiary_unit, Enum.map(tertiary_units, &{&1.unit.name, &1.unit.id}) %> | |
<% end %> | |
</div> | |
<% end %> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule RecordWeb.ElementDefinitionComponent do | |
use RecordWeb, :live_component | |
alias Record.Core.{Element, Composite, Interval} | |
alias Record.Movements | |
alias RecordWeb.CompositeComponent | |
alias Ecto.Changeset | |
def update(assigns, socket) do | |
workout = assigns.workout | |
params = %{} | |
changeset = Element.changeset(assigns.element, params) | |
movement_query = "" | |
movement_results = [] | |
{:ok, | |
socket | |
|> assign(assigns) | |
|> assign(:element_changeset, changeset) | |
|> assign(:movement_results, []) | |
|> render_add_composite() | |
} | |
end | |
defp render_add_composite(socket) do | |
render_add_composite = | |
socket.assigns.element_changeset | |
|> Ecto.Changeset.get_field(:composites) | |
|> Enum.all?(fn c -> | |
!is_nil(c.movement_id) | |
end) | |
assign(socket, :render_add_composite, render_add_composite) | |
end | |
def render(assigns) do | |
~L""" | |
<div id="<%= @id %>"> | |
<h2>Element definition</h2> | |
<%= e = form_for @element_changeset, "#", [phx_target: @myself, phx_change: :validate, phx_submit: :save] %> | |
<%= label e, :type %> | |
<%= select e, :type, ["Please select...", "amrap", "amrep", "for_time", "emom", "tabata", "ladder", "xlet"] %> | |
<%= for c <- inputs_for(e, :composites, []) do %> | |
<%= input_value(c, :uuid) %> | |
<%= live_component @socket, CompositeComponent, id: input_value(c, :uuid), composite_form: c, movement_results: @movement_results, el_form: e %> | |
<% end %> | |
<%= if @render_add_composite do %> | |
<button type="button" phx-target="<%= @myself %>" phx-click="add-composite">Add composite</button> | |
<% end %> | |
</form> | |
</div> | |
""" | |
end | |
def handle_event("add-movement", %{"movement-id" => movement_id, "composite-id" => comp_id}, socket) do | |
IO.inspect(movement_id, label: "adding movement") | |
# Clear search query | |
changeset = | |
socket.assigns.element_changeset | |
|> Ecto.Changeset.put_change(:movement_query, "") | |
existing_composites = Ecto.Changeset.get_field(changeset, :composites) | |
updated_c = | |
existing_composites | |
|> Enum.find(fn c -> c.uuid == comp_id end) | |
|> Map.put(:movement_id, movement_id) | |
index = | |
existing_composites | |
|> Enum.find_index(fn c -> c.uuid == comp_id end) | |
new_composites = | |
List.replace_at(existing_composites, index, updated_c) | |
changeset = | |
changeset | |
|> Ecto.Changeset.put_embed(:composites, new_composites) | |
{:noreply, | |
socket | |
|> assign(:movement_results, []) | |
|> assign(:element_changeset, changeset) | |
|> render_add_composite() | |
} | |
end | |
def handle_event("add-composite", values, socket) do | |
element_changeset = socket.assigns.element_changeset |> IO.inspect(label: "changeset at add-com") | |
existing_composites = Ecto.Changeset.get_field(element_changeset, :composites) | |
composites = | |
existing_composites | |
|> Enum.concat([ | |
Composite.new() | |
]) | |
|> IO.inspect(label: "updated comp at add-com") | |
changeset = | |
element_changeset | |
|> Ecto.Changeset.put_embed(:composites, composites) | |
{:noreply, | |
socket | |
|> assign(:element_changeset, changeset) | |
|> render_add_composite() | |
} | |
end | |
def handle_event("validate", %{"element" => params}, socket) do | |
IO.inspect(params, label: "validate with params") | |
changeset = Element.changeset(socket.assigns.element_changeset, params) | |
movement_results = | |
case params["movement_query"] do | |
"" -> [] | |
query -> Movements.search(query) | |
end | |
{:noreply, | |
socket | |
|> assign(:element_changeset, changeset) | |
|> assign(:movement_results, movement_results) | |
} | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment