Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simple_form default for @as overrides form values #5901

Closed
rmoorman opened this issue Aug 14, 2024 · 2 comments · Fixed by #5975
Closed

simple_form default for @as overrides form values #5901

rmoorman opened this issue Aug 14, 2024 · 2 comments · Fixed by #5975

Comments

@rmoorman
Copy link
Contributor

While using the simple_form component (that is generated by default using mix phx.new), the following problem grabbed my attention. I was building a form schema inside a live view and wanted to render that form using the simple_form component.

The example states that it should be used like this

      <.simple_form for={@form} phx-change="validate" phx-submit="save">
        <.input field={@form[:email]} label="Email"/>
        <.input field={@form[:username]} label="Username" />
        <:actions>
          <.button>Save</.button>
        </:actions>
      </.simple_form>

But I thought, that it would be more consistent to use the <.simple_form :let={f} for={@form}> in my case (because I was likely to also use inputs_for in that project). But using :let does cause the struct f to contain nil as it's name, which in turn messes up the field names and value groupings of the form (as the prefix based on the schema name is missing).

Currently, the following code:

defmodule HelloWeb.SimpleFormLetBindingLive do
  use HelloWeb, :live_view

  defmodule FormSchema do
    use Ecto.Schema
    import Ecto.Changeset

    @primary_key false
    embedded_schema do
      field(:foo, :string)
      field(:bar, :string)
    end

    def changeset(data, attrs) do
      data
      |> cast(attrs, [:foo, :bar])
      |> validate_required([:foo, :bar])
    end
  end

  @impl Phoenix.LiveView
  def handle_params(_, _, socket) do
    form = to_form(FormSchema.changeset(%FormSchema{}, %{}))
    socket = assign(socket, form: form)
    {:noreply, socket}
  end

  @impl Phoenix.LiveView
  def render(assigns) do
    ~H"""
    <.simple_form :let={f} for={@form}>
      <table>
        <tr>
          <th><code>@form.name</code></th>
          <td><code><%= inspect(@form.name) %></code></td>
        </tr>
        <tr>
          <th><code>f.name</code></th>
          <td><code><%= inspect(f.name) %></code></td>
        </tr>
      </table>

      <.input field={@form[:foo]} label="Foo" />
      <.input field={f[:bar]} label="Bar" />
    </.simple_form>
    """
  end
end

produces the following results

readme-screenshot

Which seems odd to me.

I prepared an example repository that can be used to reproduce the issue.

@josevalim
Copy link
Member

The issue is in the generated simple_form:

https://github.com/rmoorman/2024-phoenix-html-let-binding-issue/blob/master/lib/hello_web/components/core_components.ex#L192-L203

You can see it sets the default of @as to nil. You can change it in your app, I will migrate this to the Phoenix repo.

@josevalim josevalim changed the title Let binding of form structs changes form field names simple_form default for @as overrides form values Aug 15, 2024
@josevalim josevalim transferred this issue from phoenixframework/phoenix_html Aug 15, 2024
@rmoorman
Copy link
Contributor Author

Thank you @josevalim for having a look!

I suppose the suggestion of using as is about working around the problem by adding as={@form.name} or something like that within render/1? (which does indeed work)

And if there is anything else I can do to help moving this forward, please let me know.

rmoorman added a commit to rmoorman/phoenix that referenced this issue Nov 15, 2024
Remove the default `nil` value for the `as` attribute in the generated
`simple_form` core component.

This default interferes with the form name present in the form struct
provided through the component's `for` attribute when used with `:let=`.

For example, consider the following code:

```
<.simple_form :let={f} for={@Form}>
  <%= inspect(f.name) %>
  <.input field={f[:bar]} label="Bar" />
</.simple_form>
```

When rendered, `f.name` is `nil`, and the `name` attribute of the form
field only contains `bar`, missing the proper field name prefix from
the form struct:

```
<div class="mt-10 space-y-8 bg-white">
  nil
  <div data-phx-id="m9-phx-GAgAfRg6YU4XV6tC">
    <label for="bar" class="block text-sm font-semibold leading-6 text-zinc-800" data-phx-id="m10-phx-GAgAfRg6YU4XV6tC">
    Bar
    </label>
    <input type="text" name="bar" id="bar" class="mt-2 block w-full rounded-lg text-zinc-900 focus:ring-0 sm:text-sm sm:leading-6 border-zinc-300 focus:border-zinc-400">
  </div>
</div>
```

This issue been reported (over here)[phoenixframework#5901].

Fixes phoenixframework#5901
rmoorman added a commit to rmoorman/phoenix that referenced this issue Nov 15, 2024
Remove the default `nil` value for the `as` attribute in the generated
`simple_form` core component.

This default interferes with the form name present in the form struct
provided through the component's `for` attribute when used with `:let=`.

For example, consider the following code:

```
<.simple_form :let={f} for={@Form}>
  <%= inspect(f.name) %>
  <.input field={f[:bar]} label="Bar" />
</.simple_form>
```

When rendered, `f.name` is `nil`, and the `name` attribute of the form
field only contains `bar`, missing the proper field name prefix from
the form struct:

```
<div class="mt-10 space-y-8 bg-white">
  nil
  <div data-phx-id="m9-phx-GAgAfRg6YU4XV6tC">
    <label for="bar" class="block text-sm font-semibold leading-6 text-zinc-800" data-phx-id="m10-phx-GAgAfRg6YU4XV6tC">
    Bar
    </label>
    <input type="text" name="bar" id="bar" class="mt-2 block w-full rounded-lg text-zinc-900 focus:ring-0 sm:text-sm sm:leading-6 border-zinc-300 focus:border-zinc-400">
  </div>
</div>
```

This issue been reported [over here](phoenixframework#5901).

Fixes phoenixframework#5901
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants