如何从@form内容填充UI

问题描述 投票:0回答:1

我是 LiveView、Phoenix 和 Elixir 的新手,我正在努力从表单内容填充 UI。 这是我的代码中的简化版本: 我定义了一个带有一些简单字段的结构:

defmodule MyApp.MyStruct do
  defstruct some_integer: 3,
            some_string: "",
            some_bool: true
end

然后我有一个上下文:

defmodule MyApp.Context do
  alias MyApp.MyStruct

  def current_struct() do
    %MyStruct{}
  end
end

它只是返回新创建的具有默认值的结构。稍后我会实施修改。 现在,我需要显示一个填充了这些值的表单并允许修改它们。 这是我的

_live.ex
文件:

defmodule MyAppWeb.ViewLive do
  alias MyApp.MyStruct
  use MyAppWeb, :live_view

  def mount(_params, _session, socket) do
    {:ok, assign(socket, form: to_form(Map.from_struct(Context.current_struct())))}
  end

  # Here I have handle_event methods, but they don't do anything at the moment.
end

最后,这是

.heex
文件:

<div class="container mx-auto my-4">
  <.form for={@form} phx-change="change_form" phx-submit="submit_form">
    <!-- Number picker -->
    <div class="mb-4">
      <.label>I want to pick a number here:</.label>
    </div>
    <div class="flex items-center space-x-4 mb-4">
      <label class="cursor-pointer">
    <input type="radio" name="some_integer" value="3" class="hidden" checked={Context.current_struct().some_integer == 3}
    />
        <span class={"px-4 py-2 rounded-md #{if Context.current_struct().some_integer == 3, do: "bg-gray-400", else: "bg-gray-200"} hover:bg-gray-400"}>
          3 of something
        </span>
      </label>
      <!-- More of these integer options -->

    <!-- Checkbox -->
    <div class="mb-4">
      <.input
        label="I'd like this to be true or false:"
        type="checkbox"
        value={Context.current_struct().some_bool}
        field={@form[:some_bool]}
      />
    </div>

    <.button>Submit</.button>
  </.form>
</div>

上面的代码现在适用于初始值,但当我选择 7 或 10 而不是 3 时,它会停止工作。 请注意如何获取值或计算背景颜色,我使用

Context.my_struct()
进行计算。 我假设,如果我实现
handle_event("change_form"...)
并在每次更改时修改我的
current_struct()
,那么该更改也将应用于 UI。但我想仅在提交时修改实际结构,同时从
@form
获取数据。 我尝试这样做,但失败了。

当我尝试做类似的事情时

value={@form[:some_bool]}

然后就崩溃了。当我尝试使用

input_value()
时,我总是得到 nil,即使
inspect(form)
显示
some_integer
some_bool
都具有我期望它们具有的值。

请告诉我如何实现这一目标。

html forms elixir phoenix-framework phoenix-live-view
1个回答
0
投票

我假设,如果我实现handle_event(“change_form”...)并且 每次更改时修改我的 current_struct() ,那么更改也会 应用于 UI 上。但我只想修改实际结构 提交,同时从@form

获取数据

mount()
中,您可以从结构中提取值并将值存储在套接字中,这些值可用于填充
render()
中的表单。用户更改表单中的某些内容后,将调用
handle_event()
,在
handle_event()
中,您可以获得输入到表单中的值并对其执行任何您想要的操作(并且可能将输入的值保存在套接字中) .

此外,在

mount()
中,您可以将原始结构保存在套接字中,并保持不变,直到用户单击“提交”按钮。然后在里面
handle_event()
,您可以使用表单中输入的最终值来更新原始结构,然后对更新后的结构执行任何您想要的操作。

这是一个例子:

#=========  Your struct code =======

defmodule MyApp.MyStruct do
  defstruct some_integer: 3,
            some_string: "",
            some_bool: true
end

defmodule MyApp.Context do
  alias MyApp.MyStruct

  def current_struct() do
    %MyStruct{}
  end
end

#================================

defmodule DemoWeb.DemoLive do
  use DemoWeb, :live_view

  def mount(_params, _session, socket) do
    start_struct = MyApp.Context.current_struct()

    initial_form_data = %{
      input_int: start_struct.some_integer,
      input_string: start_struct.some_string,
      input_bool: start_struct.some_bool
    }

    socket = assign(socket,
        my_struct: start_struct,
        my_form: to_form(initial_form_data)
      )

    {:ok, socket}
  end

  def render(assigns) do
    ~H"""
    <.form for={@my_form} phx-change="changed" phx-submit="save">
      <.input label="Some integer:"
              field={@my_form[:input_int] }
              value = {@my_form.params.input_int }
      />
      <.input label="Some string:"
              field={@my_form[:input_string]}
              value={@my_form.params.input_string}
      />
      <.input label="Some bool:"
              field={@my_form[:input_bool]}
              value={@my_form.params.input_bool}
      />
      <.button>Submit</.button>
    </.form>
    """
  end

  def handle_event("changed",
                  %{"input_int" => entered_int,
                    "input_string" => entered_string,
                    "input_bool" => entered_bool
                    },
                  socket) do

    #Do something with entered_int, entered_string, entered_bool, e.g.
    IO.puts("[ME]: The entered integer was: #{entered_int}")
    IO.puts("[ME]: The entered string was: #{entered_string}")
    IO.puts("[ME]: The entered bool was: #{entered_bool}")

    #If needed save the entered int, string, bool in the socket using assign()

    {:noreply, socket}
  end

  def handle_event("save",
                   %{"input_int" => entered_int,
                     "input_string" => entered_string,
                    "input_bool" => entered_bool
                    },
                   socket) do

    start_struct = socket.assigns.my_struct
    updated_struct = %{start_struct | some_integer: entered_int,
                                     some_string: entered_string,
                                     some_bool: entered_bool}
    #Do something with updated_struct, e.g.:
    IO.inspect(updated_struct, label: "[ME]:")

    {:noreply, socket}
  end


end
© www.soinside.com 2019 - 2024. All rights reserved.